Object
First, Introduction
Enforcing object types in PHP can sometimes be very important. If it is missing, or because of lack of knowledge-based on incorrect programming assumptions, or simply laziness, you will see the results you don't want in a particular Web application. Especially when you are programming with PHP 4, it is very easy to use the "is_a ()" function (although there are other methods) to verify the type of object you are using. There is no doubt that coercion object types can also be used to filter input objects (other PHP classes that need to be passed as arguments to the same application).
However, PHP 4 does not expose some of the weaknesses of its object model-it may occasionally require additional code to implement features that appear in a mature object-oriented language. For a long time, this fact has been known to the PHP community. However, with the release of PHP 5, many of these highly valuable features are added as part of the improved object model. They will help to implement the development of object-based code more closely-allowing you to use specific object features.
In the above case, you should pay special attention when it comes to object type coercion. In fact, during the execution of a Web application, PHP 5 provides developers with at least two ways to examine object types-they are the "instanceof" operator and the "type hint" feature, respectively. Now go to the topic of this article, and I'll introduce the use of the "instanceof" operator in PHP 5; you'll soon find that it can be very handy to determine if the object you're using belongs to a particular type.
This article will help you understand how to implement the Coercion object type in PHP 5 with some object-oriented examples.
what you shouldn't do
To demonstrate how object type coercion is implemented in PHP 5, I will use the (X) HTML widget class, as well as a simple page builder class, and make simple modifications to fit the PHP 5 development environment.
My first example enumerates some (X) HTML widget classes that derive from an abstract base class "HtmlElement" that skips checks to their input object types. Please look at the following class first:
Define abstract class ' HtmlElement '
Abstract class htmlelement{
protected $attributes;
protected function __construct ($attributes) {
if (!is_array ($attributes)) {
throw new Exception (' Invalid attribute type ');
}
$this->attributes= $attributes;
}
The abstract ' gethtml () ' method
Abstract protected function gethtml ();
}
Define specific class ' Div '-extended htmlelement
Class Div extends htmlelement{
Private $output = ' <div ';
Private $data;
Public function __construct ($attributes =array (), $data) {
Parent::__construct ($attributes);
$this->data= $data;
}
The concrete realization of ' gethtml () ' method
Public Function gethtml () {
foreach ($this->attributes as $attribute => $value) {
$this->output.= $attribute. ' = "'. $value." ';
}
$this->output=substr_replace ($this->output, ' > ',-1);
$this->output.= $this->data. ' </div> ';
return $this->output;
}
}
Define specific class ' Header1 '-extended htmlelement
Class Header1 extends htmlelement{
Private $output = '
Private $data;
Public function __construct ($attributes =array (), $data) {
Parent::__construct ($attributes);
$this->data= $data;
}
The concrete implementation of the ' gethtml () ' method
Public Function gethtml () {
foreach ($this->attributes as $attribute => $value) {
$this->output.= $attribute. ' = "'. $value." ';
}
$this->output=substr_replace ($this->output, ' > ',-1);
$this->output.= $this->data. "return $this->output;
}
}
Define specific class ' Paragraph '-extended htmlelement
Class Paragraph extends htmlelement{
Private $output = ' <p ';
Private $data;
Public function __construct ($attributes =array (), $data) {
Parent::__construct ($attributes);
$this->data= $data;
}
The concrete realization of ' gethtml () ' method
Public Function gethtml () {
foreach ($this->attributes as $attribute => $value) {
$this->output.= $attribute. ' = "'. $value." ';
}
$this->output=substr_replace ($this->output, ' > ',-1);
$this->output.= $this->data. ' </p> ';
return $this->output;
}
}
Define specific class ' Unorderedlist '-extended htmlelement
Class Unorderedlist extends htmlelement{
Private $output = ' <ul ';
Private $items =array ();
Public function __construct ($attributes =array (), $items =array ()) {
Parent::__construct ($attributes);
if (!is_array ($items)) {
throw new Exception (' Invalid parameter for list items ');
}
$this->items= $items;
}
The concrete realization of ' gethtml () ' method
Public Function gethtml () {
foreach ($this->attributes as $attribute => $value) {
$this->output.= $attribute. ' = "'. $value." ';
}
$this->output=substr_replace ($this->output, ' > ',-1);
foreach ($this->items as $item) {
$this->output.= ' <li> '. $item. ' </li> ';
}
$this->output.= ' </ul> ';
return $this->output;
}
}
As you can see, the above (X) HTML Widget class is useful when generating a specific element of a mesh, but I intentionally write the code for each class so that they are not able to verify the validity of the input parameters. As you may have thought, input parameters will be passed directly into the class builder and assigned as attributes. The problem arises: is there any mistake in doing so? Yes, there is. Now, I'm going to define my simplest page builder class and populate it with widgets like this so you can see how the input of the class is mixed with the wrong object. The following is the signature of the Page builder class:
Class pagegenerator{
Private $output = ';
Private $title;
Public function __construct ($title = ' Default Page ') {
$this->title= $title;
}
Public Function Doheader () {
$this->output= ' >title. ' </title> }
Public Function Addhtmlelement ($htmlElement) {
$this->output.= $htmlElement->gethtml ();
}
Public Function Dofooter () {
$this->output.= ' </body> }
Public Function fetchhtml () {
return $this->output;
}
}
Now we start instantiating some (X) HTML widget objects and passing them to the corresponding generator class, as shown in the following example:
try{
Generate some HTML elements
$h 1=new Header1 (Array (' name ' => ' Header1 ', ' class ' => ' Headerclass '), ' Content for H1
Element goes here ');
$div =new Div (Array (' name ' => ' Div1 ', ' class ' => ' Divclass '), ' Content for div element
Goes here ');
$par =new Paragraph (Array (' name ' => ' par1 ', ' class ' => ' Parclass '), ' Content for Paragraph
Element goes here ');
$ul =new unorderedlist (Array (' name ' => ' List1 ', ' class ' => ' ListClass '), array
(' item1 ' => ' value1 ', ' item2 ' => ' value2 ', ' item3 ' => ' value3 '));
Instantiating a page builder class
$pageGen =new page Builder ();
$pageGen->doheader ();
Add ' HtmlElement ' object
$pageGen->addhtmlelement ($h 1);
$pageGen->addhtmlelement ($DIV);
$pageGen->addhtmlelement ($par);
$pageGen->addhtmlelement ($ul);
$pageGen->dofooter ();
Show Mesh surface
echo $pageGen->fetchhtml ();
}
catch (Exception $e) {
echo $e->getmessage ();
Exit ();
}
After running the above PHP code, the result you get is a simple Web page-it contains some of the (X) HTML objects that you created earlier. In this case, if for some reason the Web page Builder class receives an incorrect object and invokes its "addhtml ()" method, it is easy to understand what will happen. Here, I have redefined the conflicting conditions here-by using a non-existent (X) HTML Widget object. Please look at the following code again:
try{
Generate some HTML elements
$h 1=new Header1 (Array (' name ' => ' Header1 ', ' class ' => ' Headerclass '), ' Content for H1
Element goes here ');
$div =new Div (Array (' name ' => ' Div1 ', ' class ' => ' Divclass '), ' Content for div element
Goes here ');
$par =new Paragraph (Array (' name ' => ' par1 ', ' class ' => ' Parclass '), ' Content for Paragraph
Element goes here ');
$ul =new unorderedlist (Array (' name ' => ' List1 ', ' class ' => ' ListClass '), array
(' item1 ' => ' value1 ', ' item2 ' => ' value2 ', ' item3 ' => ' value3 '));
Instantiating a page builder class
$pageGen =new page Builder ();
$pageGen->doheader ();
Add ' HtmlElement ' object
$pageGen->addhtmlelement ($fakeobj)//Transfer of objects that do not exist
To this method
$pageGen->addhtmlelement ($DIV);
$pageGen->addhtmlelement ($par);
$pageGen->addhtmlelement ($ul);
$pageGen->dofooter ();
Show Mesh surface
echo $pageGen->fetchhtml ();
}
catch (Exception $e) {
echo $e->getmessage ();
Exit ();
}
In this case, as shown in the following line:
$pageGen->addhtmlelement ($fakeobj)//To pass the nonexistent object to this method
A non-existent (X) HTML Widget object is passed to the page builder class, which can cause a fatal error:
Fatal Error:call to a member function on a non-object in
Path/to/file
What do you think? This is the direct penalty for not checking the type of object passed to the generator class! So be sure to keep this in mind when writing your script. Fortunately, there is a simple solution to these problems, and this is the power of the "instanceof" operator. If you want to see how this operator is used, please read on.
[1] [2] Next page