Enforcing Object Types in PHP: Using the Type Hinting Feature in PHP 5

Here we are again. Welcome to the last tutorial of the series “Enforcing object types in PHP.” As this article’s title suggests, this series introduces the basics of object type enforcement in PHP, covering some of the most common methods for checking types of objects in both PHP 4 and PHP 5 respectively.

Introduction

As you’ll hopefully recall, in the previous article I explained the key points of using the “instanceof” operator available in PHP 5, in order to check the type of objects that eventually could be passed as input arguments to other PHP classes across the same Web application.

True to form, this operator is very useful in cases where filtering objects is a must, and of course when the flow of an application must be moved to different code blocks, in accordance with the type of object aggregated to a particular class. Additionally, you can use the “instanceof” operator for checking whether certain objects are implementers of a specific interface too. As you can see, possibilities for utilizing this operator in PHP 5 applications are certainly numerous.

Now, returning to the subject of this last tutorial, I’ll introduce another method for enforcing object types in PHP 5: the “Type Hinting” feature. It can also be used in conjunction with the “instanceof” operator that you learned about before, in order to develop PHP applications that implement thorough routines for filtering unwanted objects. Generally speaking, when you finish reading this article, you should be armed with a few more methods for forcing object types in PHP, in this way expanding your overall knowledge of object-oriented programming. 

With the formalities out of the way, let’s get started.

{mospagebreak title=The “Type Hinting” feature of PHP 5: taking an in-depth look}

If you’ve been working with PHP 5 for a while, then you’ll probably know what “Type Hinting” is about. If you don’t, let me point you in the right direction. In short, the “Type Hinting” feature will allow you to force parameters of functions (or methods) to be objects of a specific type. As you’ll see, this is very useful for filtering input objects that are passed to a class method, without having to worry whether these objects belong to the correct type or not. If the condition isn’t met, a fatal error is triggered.

The basic syntax of “Type Hinting” can be seen in the following example:

// class ‘MessageLister’
class MessageLister {
    public function __construct(Message $message) {
        echo $message->getMessage();
    }
}
// class ‘Message’
class Message {
    public $message;
    public function __construct($message) {
        $this->message=$message;
    }
    public function getMessage(){
        return $this->message;
    }
}

As you can see, in the above example I defined two simple classes. The first one, “MessageLister,” takes care of displaying basic string messages, while the second one, “Message,” stores the message passed as parameter as a class property. Now, if you turn your attention to the first class, you’ll notice it forces its $message incoming argument to be an object of type “Message.” If this condition isn’t satisfied, then the script will trigger a fatal error. To clarify this concept, study the example listed below:

$message=new Message(‘This is a test string’);
$msglister=new MessageLister($message); // displays “This is a
test string’;
$message=’This is a test string’;
$msglister=new MessageLister($message); // throws a fatal error.
$message is not of type ‘Message’

In the first case, the above snippet will display the test string as one would normally expect, while in the second example, a fatal error is triggered, since the test string isn’t an object of type “Message.” That was simple, wasn’t it?

Right, I hope this basic example helped you to understand the functionality of “Type Hinting” in PHP 5. Now that you know how this feature works, let’s use it for improving the web page generator class that I showed you in my previous tutorial, so you can have gain an accurate idea of how “Type Hinting” can work for you in applications that use object type enforcing. Let’s move on together to learn how this is done.

{mospagebreak title=A practical example: using “Type Hinting” within a web page generator class}

In order to utilize the web page generator class that I wrote in my previous article, let me first list the set of (X)HTML widget classes, useful for rendering page elements. As you’ll recall, these widget classes looked like this:

// 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;
    }
    // abstract ‘getHTML()’ method
    abstract protected function getHTML();
}
class Div extends HTMLElement{
    private $output=’<div ‘;
    private $data;
    public function __construct($attributes=array(),$data){
        if(!$data instanceof HTMLElement&&!is_string($data)){
            throw new Exception(‘Invalid parameter type’);
        }
        parent::__construct($attributes);
        $this->data=$data;
    }
    // concrete implementation for ‘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 instanceof HTMLElement)?
$this->data->getHTML():$this->data;
        $this->output.=’</div>’;
        return $this->output;
    }
}
class Header1 extends HTMLElement{
    private $output=’<h1 ‘;
    private $data;
    public function __construct($attributes=array(),$data){
        if(!$data instanceof HTMLElement&&!is_string($data)){
            throw new Exception(‘Invalid parameter type’);
        }
        parent::__construct($attributes);
        $this->data=$data;
    }
    // concrete implementation for ‘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 instanceof HTMLElement)?
$this->data->getHTML():$this->data;
        $this->output.=’</h1>’;
        return $this->output;
    }
}
class Paragraph extends HTMLElement{
    private $output=’<p ‘;
    private $data;
    public function __construct($attributes=array(),$data){
        if(!$data instanceof HTMLElement&&!is_string($data)){
            throw new Exception(‘Invalid parameter type’);
        }
        parent::__construct($attributes);
        $this->data=$data;
    }
    // concrete implementation for ‘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 instanceof HTMLElement)?
$this->data->getHTML():$this->data;
        $this->output.=’</p>’;
        return $this->output;
    }
}
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;
    }
    // concrete implementation for ‘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.=($item instanceof
HTMLElement)?’<li>’.$item->getHTML().’</li>’:'<li>’.$item.’</li>’;
        }
        $this->output.=’</ul>’;
        return $this->output;
    }
}

After defining the bunch of (X)HTML widget classes, which were originally created as subclasses of the abstract “HTMLElement” class, it’s time to list the web page generator class in question. Remember that it also uses the “instanceof” operator within its “addHTMLElement” method, in order to accept only objects of type “HTMLElement.”  The code listed below should refresh your memory of how this class looks:

class PageGenerator{
    private $output=”;
    private $title;
    public function __construct($title=’Default Page’){
        $this->title=$title;
    }
    public function doHeader(){
        $this->output=’<html><head><title>’.$this-
>title.’</title></head><body>’;
    }
    public function addHTMLElement($htmlElement){
        if(!$htmlElement instanceof HTMLElement){
            throw new Exception(‘Invalid (X)HTML element’);
        }
        $this->output.=$htmlElement->getHTML();
    }
    public function doFooter(){
        $this->output.=’</body></html>’;
    }
    public function fetchHTML(){
        return $this->output;
    }
}

Now, did you recall the signature for the above class? Fine, now allow me introduce a small change into its definition, particularly within its “addHTMLElement()” method, by replacing the corresponding “instanceof” operator with the “Type Hinting” feature:

class PageGenerator{
    private $output=”;
    private $title;
    public function __construct($title=’Default Page’){
        $this->title=$title;
    }
    public function doHeader(){
        $this->output=’<html><head><title>’.$this-
>title.’</title></head><body>’;
    }
    // type hinting is applied to input objects
    public function addHTMLElement(HTMLElement $htmlElement){
        $this->output.=$htmlElement->getHTML();
    }
    public function doFooter(){
        $this->output.=’</body></html>’;
    }
    public function fetchHTML(){
        return $this->output;
    }
}

At this point, you’ll agree with me that the improved class listed above looks very interesting now. Notice the implementation of “Type Hinting” within the pertinent “addHTMLElement()” method, in order to force all objects to be of type “HTMLElement”:

public function addHTMLElement(HTMLElement $htmlElement){
    $this->output.=$htmlElement->getHTML();
}

Now that you know how “Type Hinting” has been implemented within the web page generator class you saw above, the next thing to do is set up an example, which hopefully will demonstrate the advantages of this handy feature. Therefore, go ahead and read the next section.

{mospagebreak title=Putting “Type Hinting” to work: building object-based web documents}

Having at my disposal the set of (X)HTML widget classes, together with the corresponding web page generator class, creating a web document is as simple as instantiating some objects of type “HTMLElement”, and then passing them as parameters to the respective “addHTMLElement()” method of this class. The snippet shown below illustrates the process for constructing programmatically a simple web page:

try{
    $h1=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′));
    // instantiate a ‘PageGenerator’ object
    $pageGen=new PageGenerator();
    $pageGen->doHeader();
    // add ‘HTMLElement’ objects
    $pageGen->addHTMLElement($h1);
    $pageGen->addHTMLElement($div);
    $pageGen->addHTMLElement($par);
    $pageGen->addHTMLElement($ul);
    $pageGen->doFooter();
    echo $pageGen->fetchHTML();
}
catch(Exception $e){
    echo $e->getMessage();
    exit();
}

As the above script shows, after spawning a few (X)HTML widget objects, the process for building the web document is really straightforward. As long as the appropriate objects are passed to the “addHTMLElement()” method, the script will work with no glitches at all. Nevertheless, see what happens when I try to pass invalid data to this method:

try{
    $h1=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’);
    $teststr=’This is only a test string, and will trigger a
fatal error’;
    // instantiate a ‘PageGenerator’ object
    $pageGen=new PageGenerator();
    $pageGen->doHeader();
    // add ‘HTMLElement’ objects
    $pageGen->addHTMLElement($h1);
    $pageGen->addHTMLElement($div);
    $pageGen->addHTMLElement($par);
    $pageGen->addHTMLElement($teststr); // here this method
trigger a fatal error;
    $pageGen->doFooter();
    echo $pageGen->fetchHTML();
}
catch(Exception $e){
    echo $e->getMessage();
    exit();
}

As you may have already guessed, in this case the above script will raise a fatal error whenever the test string is passed to the “addHTMLElement()” method, since the inclusion of “Type Hinting” forces input objects to be only of type “HTMLElement”:

Fatal error: Argument 1 must not be null in path/to/file

Simple and powerful, right? Now you have learned how “Type Hinting” can be implemented within your own PHP 5 applications. Of course, as in most cases, a good understanding of its corresponding theory in conjunction with the development of numerous examples is the best approach to follow.

Bottom line

Finally, this series has concluded. Over its three articles, I discussed and explained in a friendly format, different approaches for enforcing type of objects in PHP applications. Ranging from the use of the “is_a()” function in PHP 4, to the implementation of the “instanceof” operator and “Type Hinting” in PHP 5, hopefully the experience has been enjoyable and instructive.

Even though the methods for enforcing object types that I described in this series certainly are not the only ones, definitely you’ll find that they are the most used in PHP. Thus, if you want to take your applications to a more professional level, you may want to consider using some of the approaches I discussed here. See you soon! 

Google+ Comments

Google+ Comments