Child Class editing Parent Class Property
I've looked at similar questions like this, and none of the solutions offered within them seems to answer my question.
This is the code I have so far (just learning OOP):
<?php
class page {
var $ot;
function begin(){
$this->ot = '';
}
function finish(){
echo $this->ot;
}
class forms extends page {
function __construct($form_action, $form_type){
$this->ot .= '<form action=' . $form_action . ' method=' . $form_type . ' />';
}
function create_input($type, $name){
$this->ot .= '<input type="' . $type . '" name="' . $name . '" /><br />';
}
function create_submit($value){
$this->ot .= '<input type="submit" value="' . $value . '" />';
}
function __destruct(){
$this->ot .= '</form>';
}
}
class labels extends page {
function create_label($label){
$this->ot .= '<label>' . $label . ' </label>';
}
}
$page = new page();
$page->begin();
$newform = new forms('/class_lib.php', 'GET');
$newlabels = new labels();
$newlabels->create_label('Username:');
$newform->create_input('text', 'username');
$newlabels->create_label('Password:');
$newform->create_input('p开发者_StackOverflow社区assword', 'password');
$page->finish();
?>
For some reason, this code does not output anything to the browser. However, if I change the child classes forms and labels to echo their output instead of storing it in the parent variable the code seems to spring to life and works as intended.
Excuse my ignorance as I am new to OOP.
Thanks!
$ot
is an object-property. This means, that every object of the class page
or any subclass has its own "version" of $ot
. Now you instanciate some objects and set some values, but at the end, when you call $page->finish();
$page->ot
is empty anyway.
In OOP you have the classes (types) and instances of the classes (objects). The $ot
property is what you call an instance variable, it belongs to the instances (objects) you create and is not a property of the class itself.
By making forms a subclass of page, you get what you call a "is a" relationship between the classes. That means that forms will inherit the structure of the page class. Modifying the property of a subclass object will not affect the superclass objects or any other object in this case.
When you first create a page object, that object has a $ot
property. When you create a object of type forms, that object has its own $ot
property.
To understand the concepts of OOP I would recommend you to read some tutorials. You could start by reading the Class, Instance and Inheritance parts of this wikipedia article:
http://en.wikipedia.org/wiki/Object-oriented_programming
The objects are not really connected.
You create three new objects, but they never reference each other.
Try this
// Create a new form
$newform = new forms('/class_lib.php', 'GET');
$newform->create_input('text', 'username');
$newform->create_input('password', 'password');
// Output the form, it can use the finish() method because it extends page
$newform->finish();
This will work and output the <input>
elements, but your label
class isn't plugged in to the $newForm
to do anything, its just created and is completely separate.
EDIT - bored this evening....
You will need PHP5 to run this, its not perfect, but its a good start! I have defined the following an interface called renderable and classes called element, input, label and form
// An interface describes the methods that a class must use
interface renderable
{
// Any classes that implement the renderabe interface must define a method called render()
function render();
}
// This abstract class can never be created, so you can never do new element(), it implements renderable
abstract class element implements renderable
{
// Set up some variables for all elemnts
var $attribs = array();
var $name = "";
var $type = "";
// The construct for a element needs a type and a name
function __construct($type, $name)
{
$this->name = $name;
$this->type = $type;
}
// Set an attribute for the element
function setAttribute($name, $value)
{
$this->attribs[$name] = $value;
}
// Get the name of this element
function getName()
{
return $this->name;
}
// The render function outputs an element
function render()
{
// Output the start of the element eg <input
echo "<" . $this->type . " ";
// each attribute eg class='blue'
foreach($this->attribs as $name => $value)
echo " " . $name . "='" . $value ."' ";
// end the element
echo " />";
echo "<br />";
}
}
// The input element extends element but is not abstract
class input extends element
{
// Nothing is overridden here from the parent class element
}
// The label element extends element but is not abstract
class label extends element
{
// Define a new var called label, this is special for the label element
var $label = "";
// Override the contruct for element to only accept a name, this
// is because the label element type will always be label
function __construct($name)
{
$this->name = $name;
$this->type = "label";
}
// Set the label var
function setLabel($label)
{
$this->label = $label;
}
// Override the render function, this means that label has its own render function
// and does not use the function from the abstract class element
function render()
{
echo "<" . $this->type . " ";
foreach($this->attribs as $name => $value)
echo " " . $name . "='" . $value ."' ";
echo " >";
// Here the special label content is displayed
echo $this->label;
echo "</label>";
}
}
// A form extends element
class form extends element
{
// A form has some new vars
var $elements = array();
var $labels = array();
var $action;
var $method;
// Override the contruct and use name, action and method
// There are default values for action and method so they are not required
function __construct($name, $action = "/", $method = "GET")
{
$this->name = $name;
$this->type = "form";
$this->action = $action;
$this->method = $method;
}
// Add a new element to the form along with its label
function appendElement($element, $label)
{
// Add these to an array inside this class
$this->elements[$element->getName()] = $element;
$this->labels[$label->getName()] = $label;
}
// Override the render function
function render()
{
// Output the form's start along with the method and action
echo '<' . $this->type. ' ' . 'action="' . $this->action . '" method="' . $this->method . '" />';
// Iterate over the array of elments and render each one
foreach($this->elements as $name => $ele)
{
// Render the label for the current element
$this->labels[$name]->render();
// Render the element
$ele->render();
}
// End the form
echo "</form>";
}
}
// Create form with name, action and method
$form = new form("login", "/login.php", "POST");
// Create input username
$ele = new input("input", "username");
// Set type
$ele->setAttribute("type", "text");
// Set a class
$ele->setAttribute("class", "blue");
// Create a label for the username long with its content
$label = new label("username");
$label->setLabel("Username: ");
// Add the username element and its label
$form->appendElement($ele, $label);
// Repeat for password
$ele = new input("input", "password");
$ele->setAttribute("type", "password");
$label = new label("password");
$label->setLabel("Password: ");
$form->appendElement($ele, $label);
// Render the form
$form->render();
Since you're learning OOP, it's time to learn about Abstract
Classes (PHP Manual)!
An abstract class is a sort of skeleton class that defines a series of generic functions. An abstract class can never be instantiated (i.e., you cannot call new AbstractClass
), but can be extend
ed by other classes. This allows us to define something generic and repeatable, say, and HTML Element, and then extend that to specific HTML elements as time goes on. Here is a sample implementation of that concept.
WARNING: I am not saying that this implementation is a great idea; learning purposes only!
First, some abstract classes to define how this stuff ought to work.
abstract class HTMLWriter
{
protected $html = '';
protected $tagName = null;
protected $selfClosing = false;
protected $elements = array();
protected $attributes = array();
protected $closed = false;
abstract public function __construct();
public function addElement(HTMLWriter $element)
{
if ($this->closed || $this->selfClosing) {
return;
}
$element->close(); // automatic!
$this->elements[] = $element->write();
}
public function addElements() {
foreach (func_get_args() as $arg) {
if ($arg instanceof HTMLWriter) {
$this->addElement($arg);
}
}
}
public function addAttribute($name, $value)
{
return $this->attributes[$name] = $value;
}
public function write()
{
if (!$this->closed) {
$this->close();
}
return $this->html;
}
public function close()
{
$this->closed = true;
$this->html = '<' . $this->tagName;
foreach ($this->attributes AS $attr => $val) {
$this->html .= ' ' . $attr . '="' . $val . '"';
}
if ($this->selfClosing) {
$this->html .= '/>';
return;
}
$this->html .= '>';
foreach($this->elements as $elem) {
$this->html .= $elem;
}
$this->html .= '</' . $this->tagName . '>';
}
}
abstract class HTMLWriterWithTextNodes extends HTMLWriter
{
//abstract public function __construct();
public function addText($text)
{
$this->elements[] = htmlentities($text);
}
public function addTextRaw($text)
{
$this->elements[] = $text;
}
}
And then the concrete implementations of those classes:
note: a concrete class is any non-abstract class, although this term loses its meaning when applied to classes that are not extensions of abstract classes.
class Form extends HTMLWriter
{
public function __construct($action, $method, $can_upload = false)
{
$this->tagName = 'form';
$this->addAttribute('action', $action);
$this->addAttribute('method', $method);
if ($can_upload) {
$this->addAttribte('enctype','multipart/form-data');
}
}
}
class Input extends HTMLWriter
{
public function __construct($type, $name, $id = null)
{
$this->tagName = 'input';
$this->selfClosing = true;
$this->addAttribute('type', $type);
$this->addAttribute('name', $name);
if (!is_null($id)) {
$this->addAttribute('id', $id);
}
}
// overrides
public function addElement()
{
return false;
}
}
class Label extends HTMLWriterWithTextNodes
{
public function __construct($labelText = null, $for = null)
{
$this->tagName = 'label';
if (!is_null($labelText)) {
$this->elements[] = $labelText;
}
if (!is_null($for)) {
$this->addAttribute('for', $for);
}
}
}
class GenericElement extends HTMLWriterWithTextNodes
{
public function __construct($tagName, $selfClosing = false)
{
if (empty($tagName)) {
$this->closed = true;
$this->html = '';
return;
}
$this->tagName = $tagName;
$this->selfClosing = (bool)$selfClosing;
}
}
Finally, let's instantiate and use our new classes
$form = new Form('/class_lib.php','get');
$username = new Input('text','username','username');
$password = new Input('password','password','password');
$submit = new Input('submit','login');
$submit->addAttribute('value','login');
$ulabel = new Label('Username: ', 'username');
$plabel = new Label('Password: ','password');
$br = new GenericElement('br',true);
$form->addElements(
$ulabel, $username, $br,
$plabel, $password, $br,
$submit
);
echo $form->write();
Output:
<form action="/class_lib.php" method="get"><label for="username">Username: </label><input type="text" name="username" id="username"/><br/><label for="password">Password: </label><input type="password" name="password" id="password"/><br/><input type="submit" name="login" value="login"/></form>
Hooray for abstract classes!
精彩评论