Introducing Visitor Objects in PHP 5

Although the article’s title may seem a bit intimidating, the truth is that things are much simpler than you think. Like many other programming languages, PHP also allows you to construct and use visitor objects with minor hassles. But, before I go deeper into the subject, first let’s ask ourselves the following question: what are visitor objects, after all?

Introduction

Well, if you’ve been using design patterns for a while in your PHP applications, then you’ve probably heard about the Visitor pattern. If you haven’t yet, let me give you a short description of what this pattern does. In simple terms, when it’s applied appropriately, the pattern allows you to build up objects that literally visit other objects to obtain information about the target objects. This process is usually done by inputting the visitors into the visited objects via a concrete method. 

To put it simply way, suppose that you have a bunch of objects that represent, in the software universe, the profiles of several users. This example looks pretty familiar, doesn’t it? Well, it’s possible to create a set of objects that “visit” these users and obtain certain information related to them, such as First and Last Name, user IDs, email addresses, and so forth. The exciting aspect of this situation is that this entire process can be performed programmatically, by using some simple classes, and as you know, PHP makes working with objects a no-brainer task.

So that’s a small portion of theory of building visitor objects. Nevertheless, you’ll agree with me that one of the most interesting aspects of design patterns is precisely their practical side. Therefore, considering this undeniable fact, in conjunction with your permanent wish for extending your background in object-oriented programming with PHP, over the course of this series I’ll be showing you some useful examples of how to build visitor objects, and more specifically how to include them in real-world applications.

Assuming that creating visitor objects with PHP has already caught your attention, let’s introduce ourselves to the subject and start learning more about it.

{mospagebreak title=An introductory example}

I strongly believe that seemingly-complex topics are best understood by simple methods, so I’m going to introduce a very manageable example of how to create and use visitor objects in PHP 5.

My plan basically consists of developing a couple of simple classes, which store generic information in arrays and text files. Once these classes have been defined and correctly understood, I’ll use a few visitor objects to obtain basic information about the classes in question.

Thus, I’ll begin defining a generic abstract “VisitedData” class, and then derive two subclasses. As I mentioned before, here is the signature of the first abstract class:

// define abstract ‘VisitedData’
abstract class VisitedData{
    abstract function acceptVisitator(Visitator $visitator);
}

As you can appreciate, the class shown above implements a generic structure for creating objects that will be visited by the respective visitor objects. Regarding this concept, you can see that this class presents an abstract “acceptVisitator()” method, which will be the entry point for accepting visitor objects.

Now, having defined the previous abstract class, let me show you the pair of sub classes that implement the method listed above. First of all, here is the definition of the “VisitedArray” class:

// extend ‘VisitedArray’ class from abstract ‘VisitedData’ class
class VisitedArray extends VisitedData{
    private $elements=array();
    public function __construct(){}
    // add new element to array
    public function addElement($element){
        if(!$element){
            throw new Exception(‘Invalid array element’);
        }
        $this->elements[]=$element;
    }
    // get array size
    public function getSize(){
        if(!$size=count($this->elements)){
            throw new Exception(‘Error counting array elements’);
        }
        return $size;
    }
    // accepts ‘visitator’ object and call ‘visitArray()’ method
    public function acceptVisitator(Visitator $visitator){
        $visitator->visitArray($this);
    }
}

In this case, the above child class perform some basic tasks, like storing plain strings in the predefined “elements” array. However, I strongly recommend that you focus your attention on the “acceptVisitator()” method, since it’s the most relevant one with reference to implementing the visitor pattern.

Please, notice how this method accepts a visitor object, which uses the “visitArray()” method, to obtain information about the visited object. This schema is extremely common when using the visitor pattern, thus you should keep it in mind for further reference: in all cases, the visited object is passed as a parameter to the respective visitor, in order to get additional information about it.

Now, do you see how a visitor object uses its own method for retrieving relevant data about the visited one? That’s exactly the expected behavior of objects when using the visitor pattern! Again, try to bear this interaction schema in mind, since in most cases it will be nearly the same.

So far, I showed you how to write an array manipulation class that accepts a visitor object. However, I’d like to extend the prior example and create another sample class, which also takes up a visitor, and specifically saves data to a given text file.

In the upcoming section, I’ll define the structure of this brand new class, therefore go ahead and read the next few lines. It’ll be really instructive, trust me.

{mospagebreak title=Defining another sample class}

As I expressed earlier, I want to expand the practicality of the previous example by coding another sample class, which also accepts a visitor object. In this case, this new class is called “VisitedFile,” and its signature is as follows:

// extend ‘VisitedFile’ class from abstract ‘VisitedData’ class
class VisitedFile extends VisitedData{
    private $filePath;
    public function __construct
($filePath=’default_path/data.txt’){
        $this->filePath=$filePath;
    }
    // add new line to data file
    public function addLine($line){
        if(!$fp=fopen($this->filePath,’a+’)){
            throw new Exception(‘Error opening data file’);
        }
        fwrite($fp,$line.”n”);
        fclose($fp);
    }
    // get file size
    public function getSize(){
        if(!$size=filesize($this->filePath)){
            throw new Exception(‘Error determining size of data
file’);
        }
        return $size;
    }
    // get number of file lines
    public function getNumLines(){
        if(!$numLines=count(file($this->filePath))){
            throw new Exception(‘Error determining number of
lines for data file’);
        }
        return $numLines;
    }
    // accepts ‘visitator’ object and call ‘visitFile()’ method
    public function acceptVisitator(Visitator $visitator){
        $visitator->visitFile($this);
    }
}

As shown above, the functionality of the new “VisitedFile” class is only limited to saving plain strings to a given text file. However, my intention here is that you pay attention to the respective “acceptVisitator()” method, since it’s closely similar to the previous one that you learned in the past section.

Also, on this occasion, the visitor will call its visiting method, and pass to it the visited object, with the purpose of getting additional information about it. As I said before, this model of object interaction is practically identical for all the cases where the visitor pattern is implemented. I hope you’ll have no problem grasping this concept.

Okay, at this point you learned how to create two subclasses that accept visitor objects, but… how can these visitors be created? Do you have any clue about that? Well, to dissipate any possible questions, over the course of the next section, I’ll show you how to define the structure of visitor objects.

To learn how this will be done, click on the link below and continue reading.

{mospagebreak title=Defining the structure of a visitor}

Until now, you learned how to build some classes that are capable of accepting a visitor object, which comes in handy for retrieving information about these classes. Nevertheless, the structure of a visitor class still remains undefined. This is a strong motivation for illustrating how a visitor object can be created. I begin this process by creating its abstract signature, and then by deriving some subclasses.

That said, here is the structure of a highly generic visitor class. Please, examine the code listed below:

// define abstract ‘Visitator’ class
abstract class Visitator{
    abstract function visitArray(VisitedArray $visitedArray);
    abstract function visitFile(VisitedFile $visitedFile);
} 

As you can see, this entirely new abstract class represents the generic model of a visitor object, and exposes the two corresponding abstract methods, to visit the pair of classes that were defined in the previous section.

At this stage, if you study in detail the definition of the above class, you’ll realize how a visitor visits the pertinent target classes, since its two methods accept them as input arguments. Indeed, the relationship between objects here is very comprehensible.

All right, now that you know how an abstract visitor looks, it’s time to derive at least one child visitor, in such a way that it can implement the prior abstract methods. Regarding this point, below is the definition of a concrete visitor class:

// define ‘DataVisitator’ class
class DataVisitator extends Visitator{
    private $arrayInfo;
    private $fileInfo;
    // get info about visited array
   public function visitArray(VisitedArray $visitedArray){
        $this->arrayInfo=’Visited array contains the following
number of elements: ‘.$visitedArray->getSize();
    }
    // return info about visited array
    public function getArrayInfo(){
        return $this->arrayInfo;
    }
    // get info about visited file
    public function visitFile(VisitedFile $visitedFile){
        $this->fileInfo=’Visited file has a size of
‘.$visitedFile->getSize().’ bytes, and contains ‘.$visitedFile-
>getNumLines().’ lines’;
    }
    // return info about visited file
    public function getFileInfo(){
        return $this->fileInfo;
    }
}

As you can see, on this occasion I created a concrete visitor class, which I called “DataVisitator.” This class offers a concrete implementation of the “visitArray()” and “visitFile()” methods respectively, to obtain information about the size of the visited array in question, as well as get the dimension of the pertinent visited file.

At this point, it should be clear to you how a visitor can “inspect” the properties of the visited objects, and retrieve relevant information about them. After all, implementing the visitor pattern with PHP 5 isn’t difficult at all, but I believe this article would be rather incomplete if I didn’t show you a hands-on example that uses all the classes that I defined before.

Speaking of that, over the next few lines, you’ll learn how the corresponding visitor object collects data that belongs to the visited classes. As usual, see you in the next section.

{mospagebreak title=A visitor object in action}

As I mentioned earlier, correctly understanding the behavior of a visitor object is a process that relies mostly on practical examples. That’s exactly the reason why I coded a short script (shown below) which demonstrates the functionality of the visitor pattern. Look at the following code listing:

try{
    // instantiate ‘VisitedArray’ object
    $visitedArray=new VisitedArray();
    // add some elements to the array
    $visitedArray->addElement(‘Element 1′);
    $visitedArray->addElement(‘Element 2′);
    $visitedArray->addElement(‘Element 3′);
    $visitedArray->addElement(‘Element 4′);
    $visitedArray->addElement(‘Element 5′);
    // instantiate ‘DataVisitator’ object
    $dataVisitator=new DataVisitator();
    // accept visitor object
    $visitedArray->acceptVisitator($dataVisitator);
    $dataVisitator->visitArray($visitedArray);
    // display info about visited array
    echo ‘<p>Visitor object determined the following information
about visited array:</p>’;
   echo $dataVisitator->getArrayInfo();
   // instantiate ‘VisitedFile’ object
    $visitedFile=new VisitedFile();
    // add some lines to the file
    $visitedFile->addLine(‘This is line 1′);
    $visitedFile->addLine(‘This is line 2′);
    $visitedFile->addLine(‘This is line 3′);
    $visitedFile->addLine(‘This is line 4′);
    $visitedFile->addLine(‘This is line 5′);
    // accept visitor object
    $visitedFile->acceptVisitator($dataVisitator);
    $dataVisitator->visitFile($visitedFile);
    // display info about visited file
    echo ‘<p>Visitor object determined the following information
about visited file:</p>’;
   echo $dataVisitator->getFileInfo();
}

catch(Exception $e){
    echo $e->getMessage();
    exit();
}

Although the above script may seem simple at first glance, it shows in a nutshell the functionality of a visitor object. Notice how this object retrieves the size of the visited array, after populating it with some data, as well as how it obtains the size of the visited file once some strings have been added to this file.

Of course, the output generated by the previous script is as following:

Visitor object determined the following information about visited
array:
Visited array contains the following number of elements: 5

Visitor object determined the following information about visited
file:
Visited file has a size of 600 bytes, and contains 5 lines

Wasn’t that great? After the corresponding visited classes neatly allowed the visitor object to inspect their properties, the corresponding information is outputted to the browser. Just let your mind go one step further and think about the implementation of a visitor object capable of inspecting all the visible properties of any visited classes. Here you have the foundations for doing that!

Wrapping up

Unfortunately, we’ve come to the end of the initial part of our discussion. In this first article of the series, I walked you through the basics of implementing the visitor pattern with PHP 5. I hope that all the code samples that you saw here will serve as an introduction to applying this pattern in a more sophisticated environment. From this moment on, it’s up to you.

In the second tutorial, I’ll show you more practical examples of how to apply the visitor pattern with PHP 5. Stay tuned!

Google+ Comments

Google+ Comments