Inheritance and Polymorphism in PHP: Building a Form Generator – Part II

In part two of this three-part series, we refresh our memory of Inheritance and subclasses from part one, and take our first stab at implementing a form generator.

Introduction

Welcome to Part II of the series “Inheritance and Polymorphism in PHP: Building a Form Generator.” I really hope that you found the concepts explained in the first part useful. As you may recall, in part I we introduced the OOP arena in PHP, using the capabilities of Inheritance for creating an extensible form generator.

Stepping back to refresh our memories, we defined a base form object class and derived each subclass that defines the bare bones for each form element. For the complete list of classes, please take a look at the first article, to quickly grasp how they were structured. It’s fairly simple.

In this second article, we will get a bit more complex. We’re going to complete the source code for each class definition, having an overall concept of the mechanism to make the form generator work properly.

So, it’s time to show our work in progress and fully define the subclasses for each form element. Let’s get started.

{mospagebreak title=That refreshing touch: core definition for base class and subclasses}

Since the subclasses can quite easy be entirely defined, as you’ll see in a moment, before looking at their whole source code and logic it would be useful to refresh our memory of the skeletal structure for at least a couple of them. To begin with, let’s show the code for the base class, as it was originally defined:

class formObject {

var $label;

var $name;

var $style;

function formObject($label,$name,$style){

(!is_numeric($label))?$this->label=$label:die(‘Invalid
parameter ‘.$label);

(!is_numeric($name))?$this->name=$name:die(‘Invalid
parameter ‘.$name);

(!is_numeric($style))?$this->style=$style:die(‘Invalid
parameter ‘.$style);

}

function generateHTML(){

echo ‘You are not overriding the generateHTML() method
of the formObject super class!';

}

}

The above base class is really acting as the core structure for defining any further form element. It offers three common properties ($label, $name and $style) shared by any form element, being inherited in the derived subclasses. It also offers the “generateHTML()” method, which, as we’ll see shortly, will take care of generating the proper HTML for each type of form object (text inputs, radio buttons, and so forth).

Because each subclass is rather defined in a similar fashion, let’s remember the basic definitions for the input text and the radio button objects, just to make sure that we’re heading the right way for building the form generator. The basic code for the subclass tied to a text input element looked like this:

// class definition for input text object

class inputTextObject extends formObject {

var $value;

var $maxlength;

function inputTextObject($label,$name,$style,$value,$maxlength){

parent::formObject($label,$name,$style);

// properties setup

}

function generateHTML(){

}

}

And, for radio buttons, the code was the following:

// class definition for radio button object

class radioButtonObject extends formObject {

var $value;

var $checked;

function radioButtonObject($label,$name,$style,$value,$checked=”){

parent::formObject($label,$name,$style);

// properties setup

}

function generateHTML(){

}

}

We’re not going to list the basic code for each subclass tied to a form element again! That was already done in the previous article. However, demonstrating how they looked in their original incarnation is the perfect foundation for moving forward and seeing the complete code for each subclass.

If you ever have worked with HTML forms (and who hasn’t?), then you know that they offer numerous elements. It seems that the list for all of the subclasses is rather lengthy. If you don’t take my word for it, take a look at the following section.

{mospagebreak title=There is a long list in your life: listing the full code for each subclass}

Let’s get straight to the point. First, let’s look at the subclass for input text objects. Here is its definition:

class inputTextObject extends formObject {

var $value;

var $maxlength;

function inputTextObject($label,$name,$style,$value,$maxlength){

parent::formObject($label,$name,$style);

(!is_numeric($value))?$this->value=$value:die(‘Invalid
parameter ‘.$value);

(is_int($maxlength)&&$maxlength>2&&$maxlenght<24)?
$this->maxlength=$maxlength:die(‘Invalid parameter
‘.$maxlength);

}

function generateHTML(){

$html=$this->label.'<input type=”text” name=”‘.$this-
>name.'” value=”‘.$this->value.'” class=”‘.$this-
>style.'” maxlength=”‘.$this->maxlength.'” />';

return $html;

}

}

As you can deduce from the above listed code, the subclass extends the base class, adding two extra properties: $value and $maxlength. The constructor accepts the base class parameters, plus the additional ones, and calls the base class constructor for setting up the $label, $name and $style properties. That’s very simple to understand. Also notice that the subclass exposes its own “generateHTML()” method, which generates the corresponding HTML for an text input element, according to its properties.

Now, I think that you have an approximate idea of how the rest of the subclasses will look. And certainly you’re correct. They’re similarly defined, with a few different properties, according to the type of form element treated, but all of them offer the “generateHTML()” method. So, here’s the definition for a hidden field subclass:

class hiddenFieldObject extends formObject {

var $value;

function hiddenFieldObject($label,$name,$style,$value){

parent::formObject($label,$name,$style);

(!is_numeric($value))?$this->value=$value:die(‘Invalid
parameter ‘.$value);

}

function generateHTML(){

$html='<input type=”hidden” name=”‘.$this->name.'”
value=”‘.$this->value.'” class=”‘.$this->style.'” />';

return $html;

}

}

In as similar way, we can define the subclass for a radio button element:

class radioButtonObject extends formObject {

var $value;

var $checked;

function radioButtonObject
($label,$name,$style,$value,$checked=”){

parent::formObject($label,$name,$style);

(!is_numeric($value))?$this->value=$value:die(‘Invalid
parameter ‘.$value);

($checked==’checked’||$checked==”)?$this-
>checked=$checked:die(‘Invalid parameter ‘.$checked);

}

function generateHTML(){

$html='<input type=”radio” name=”‘.$this->name.'”
value=”‘.$this->value.'” class=”‘.$this->style.'”‘;

($this->checked==’checked’)?$html.=’ checked=”‘.$this-
>checked.'” />’.$this->label:$html.=’ />’.$this->label;

return $html;

}

}

If building checkboxes is your favorite hobby (mine is building submit buttons), here is the checkbox definition:

class checkBoxObject extends formObject {

var $value;

var $checked;

function checkBoxObject($label,$name,$style,$value,$checked=”){

parent::formObject($label,$name,$style);

(!is_numeric($value))?$this->value=$value:die(‘Invalid
parameter ‘.$value);

($checked==’checked’||$checked==”)?$this-
>checked=$checked:die(‘Invalid parameter ‘.$checked);

}

function generateHTML(){

$html='<input type=”checkbox” name=”‘.$this->name.'”
value=”‘.$this->value.'” class=”‘.$this->style.'”‘;

($this->checked==’checked’)?$html.=’ checked=”‘.$this-
>checked.'” />’.$this->label:$html.=’ />’.$this->label;

return $html;

}

}

There are several subclasses to be defined. Don’t forget them. Here are the select boxes:

class selectObject extends formObject {

var $size;

var $options;

function selectObject($label,$name,$style,$size,$options=array()){

parent::formObject($label,$name,$style);

(is_integer($size)&&$size>0)?$this->size=$size:die
(‘Invalid parameter ‘.$size);

(count($options)>0)?$this->options=$options:die
(‘Invalid parameter ‘.$options);

}

function generateHTML(){

$html=$this->label.'<select name=”‘.$this->name.'”
class=”‘.$this->style.'” size=”‘.$this->size.'”>';

foreach($this->options as $option=>$value){

$html.='<option value=”‘.$value.'”>’.$option.'</option>';

}

$html.='</select>';

return $html;

}

}

At this point, half of the job is done. Let’s catch our breath, then continue defining the rest of the subclasses.

{mospagebreak title=Coming up: more subclasses}

If you think that the above class definitions are not enough for building our form generator, you’re right. There are still more form elements to be defined. So, it’s time to continue defining more form subclasses. The next one to be defined is a <textarea> element, listed below:

class textAreaObject extends formObject {

var $value;

var $wrap;

function textAreaObject($label,$name,$style,$value,$wrap=’virtual’){

parent::formObject($label,$name,$style);

(!is_numeric($value))?$this->value=$value:die(‘Invalid
parameter ‘.$value);

($wrap==’off’||$wrap==’physical’||$wrap==’virtual’)?
$this->wrap=$wrap:die(‘Invalid parameter ‘.$wrap);

}

function generateHTML(){

$html=$this->label.'<textarea name=”‘.$this->name.'”
class=”‘.$this->style.'” wrap=”‘.$this-
>wrap.'”>’.$this->value.'</textarea>';

return $html;

}

}

The above listed class for building a <textarea> element accepts two additional parameters: $value and $wrap, in order to use them for proper HTML generation. In this case, we’ve given a default value of “virtual” for the $wrap parameter.

Now let’s look at the form button elements. Its class definition is the following:

class buttonObject extends formObject {

var $value;

function buttonObject($label,$name,$style,$value){

parent::formObject($label,$name,$style);

(!is_numeric($value))?$this->value=$value:die(‘Invalid
parameter ‘.$value);

}

function generateHTML(){

$html=$this->label.'<input type=”button” name=”‘.$this-
>name.'” value=”‘.$this->value.'” class=”‘.$this-
>style.'” />';

return $html;

}

}

Our next step consists of listing the class for generating password fields. Here’s the code:

class passwordObject extends formObject {

var $maxlength;

function passwordObject($label,$name,$style,$maxlength){

parent::formObject($label,$name,$style);

(is_int($maxlength)&&$maxlength>8&&$maxlenght<24)?
$this->maxlength=$maxlength:die(‘Invalid parameter
‘.$maxlength);

}

function generateHTML(){

$html=$this->label.'<input type=”password”
name=”‘.$this->name.'” value=”‘.$this->value.'”
class=”‘.$this->style.'” />';

return $html;

}

}

Okay, let’s put in a bit more effort, and define the class for file uploads elements:

class fileObject extends formObject {

function fileObject($label,$name,$style){

parent::formObject($label,$name,$style);

}

function generateHTML(){

$html=$this->label.'<input type=”file” name=”‘.$this-
>name.'” class=”‘.$this->style.'” />';

return $html;

}

}

Let’s not forget to define the subclass for reset buttons. Here is the code:

class resetObject extends formObject {

var $value;

function resetObject($label,$name,$style,$value){

parent::formObject($label,$name,$style);

(!is_numeric($value))?$this->value=$value:die(‘Invalid
parameter ‘.$value);

}

function generateHTML(){

$html=$this->label.'<input type=”reset” name=”‘.$this-
>name.'” value=”‘.$this->value.'” class=”‘.$this-
>style.'” />';

return $html;

}

}

Finally, we’re going to show our last two classes: form image elements and submit buttons. First, here’s the code for form image elements, often used for submitting forms without using the venerable submit button:

class imageObject extends formObject {

var $value;

var $src;

var $alt;

function imageObject
($label,$name,$style,$value,$src,$alt){

parent::formObject($label,$name,$style);

(!is_numeric($value))?$this->value=$value:die(‘Invalid
parameter ‘.$value);

(!is_numeric($alt))?$this->alt=$alt:die(‘Invalid
parameter ‘.$alt);

(file_exists($src))?$this->src=$src:die(‘Invalid
parameter ‘.$src);

}

function generateHTML(){

$html=$this->label.'<input type=”image” name=”‘.$this-
>name.'” value=”‘.$this->value.'” class=”‘.$this-
>style.'” src=”‘.$this->src.'” alt=”‘.$this-
>alt.'” />';

return $html;

}

}

Finally, the class definition for a submit button:

class submitObject extends formObject {

var $value;

function submitObject($label,$name,$style,$value){

parent::formObject($label,$name,$style);

(!is_numeric($value))?$this->value=$value:die(‘Invalid
parameter ‘.$value);

}

function generateHTML(){

$html=$this->label.'<input type=”submit” name=”‘.$this-
>name.'” value=”‘.$this->value.'” class=”‘.$this-
>style.'” />';

return $html;

}

}

I must give a short disclaimer: notice that in all of the subclasses that accept a $value parameter, we’ve opted not to consider as a valid argument any numeric value. While this validation process could be leaving out some potentially valid parameters, we’ve chosen to do this based on a data type checking rather than performing validation on data length. For particular cases, just implement the validation process you believe best suits your needs.

Now we have fully defined each subclass derived from the form base class for creating the form generator. Since subclasses nicely expose the “generateHTML()” method, it is easy to figure out a technique to put all of the subclasses to work and build a complete HTML form. So, let’s try creating a regular form, using the above defined classes.

{mospagebreak title=Implementing the Form Generator: take one}

So far, we’ve seen the pieces of the form in separated classes. Having available the base “formObject” class, as well as the different derived sub classes, it’s time to instantiate some form objects and build a basic HTML form. Our first approximation would be implemented sticking to the following approach:

// include required class file

require_once(‘formclasses.php’);

// instantiate derived inputText objects from super class formObject

$textField1=&new inputTextObject(‘First
Name’,’firstname’,’textinput’,”,30);

$textField2=&new inputTextObject(‘Last
Name’,’lastname’,’textinput’,”,30);

// instantiate derived checkbox object from super class
formObject

$checkboxField=&new checkBoxObject(‘I want to receive
the weekly
newsletter.’,’newsletter’,’checkbox’,’newsletter’);

// instantiate derived submit object from super class
formObject

$submitButton=&new submitObject
(”,’send’,’submitbutton’,’Send Data’);

// make objects array

$objects=array
($textField1,$textField2,$checkboxField,$submitButton);

// generate form determining what type of object is
treated

foreach($objects as $object){

switch (get_class($object)){

case “inputtextobject”:

echo $object->label.'<input name=”‘.$object->name.'”
type=”text” maxlength=”‘.$object-
>maxlength.'” /><br />';

break;

case “checkboxobject”:

echo ‘<input name=”‘.$object->name.'” type=”checkbox”
value=”‘.$object->value.'” />’.$object->label.'<br />';

break;

case “radiobuttonobject”:

echo ‘<input name=”‘.$object->name.'” type=”radio”
value=”‘.$object->value.'” />’.$object->label.'<br />';

break;

case “submitobject”:

echo $object->label.'<input name=”‘.$object->name.'”
type=”submit” value=”‘.$object->value.'” /><br />';

break;

default:

break;

}

}

That’s our rough approximation for coding our form generator, and I must say that is really bad! Even worse, it’s dramatic. But, why are we complaining so loudly about the code? After all, we’ve been using the base class and subclasses, applying Inheritance,  and finally instantiating a few form objects, in order to build a regular HTML form. What could be so wrong? Just take a look at the section where we generate the form using an object array structure, and use a “switch” statement to determine which form object we’re dealing with.

Utilizing the “get_class()” PHP built-in function, we’re finding out what type of form element is contained in the array, and subsequently displaying the corresponding code for the element. Please forgive me about my vehemence, but switch statements are really poor and inefficient. Not only are we being redundant about HTML generation, but we’re also accessing objects properties directly! What about encapsulation? Object properties must always be accessed by the set of objects’ proper methods.

Also, the code is hiding a bigger problem. If we want to add another form element to the form generator, the updating process is really a nightmare. Definitely, this approach demonstrates how things must not be done.

So, what’s our next step to fixing the above dirty implementation? The answer is Polymorphism. Yes, even in an extremely weakly typed language such as PHP, we can take advantage of it for finding a new approach to build the form generator. Do you remember that each subclass defined presents a “generateHTML()” method? So, why don’t we get a bit smarter, using it to present a more decent solution? That’s what we’re going to put in practice in the last part of this series, demonstrating the big advantage of using polymorphic objects, and explaining its core concept definition.

Summary

In this second part of the series, we’ve finished defining the whole source code for each subclass corresponding to a form element. Also, hopefully we’ve demonstrated how poorly we could be implementing our form generator without using the advantages of Polymorphism as the previous step to fixing these major mistakes, employing its capabilities in PHP with a practical approach.

In the next part, we’ll be putting Polymorphism to work for us, presenting a new version of our form generator. In the meantime, play with the code and add your own improvements to the project. After all, that’s what collaborative work is about. See you in the third part!

[gp-comments width="770" linklove="off" ]

chat sex hikayeleri Ensest hikaye