Introducing the Composite Pattern in PHP 5

The composite pattern is one of the less commonly used patterns in PHP 5. Nevertheless, in certain situations, it is very helpful. This article, the first one in a two-part series, will introduce you to the basic concepts of the composite pattern.

Introduction

In the vast and definitely fascinating terrain of pattern-based application development with PHP, quite possibly you’ll know that there are certain patterns that are much simpler to implement than others. Actually this fact is a logical consequence of having acquired a strong background in the most common ones.

It’s highly probably that you already have a solid knowledge of some familiar topics that belong specifically to software engineering, such as what a Singleton is, or how a concrete factory class can be created with PHP by a few easy steps.

However, while there are specific design patterns that are indeed used by many developers on a frequent basis during the development of different PHP applications, the truth is that there’s a small group of them that very often remain unexplored, either because they simply can’t be applied so quickly in real world situations, or because of their rather complex implementation.

So, considering the fact that this limited set of uncommon design patterns can be potentially interesting to you (and to me, by the way), and taking into account that they do deserve at least a quick look, in this two part series I’m going to teach you how to implement the composite pattern with PHP 5.

Just in case this pattern doesn’t ring any bells to you, let offer you a quick introduction to how it works. In crude terms, when the composite pattern is applied in the context of a given application, one single object or a group of these objects will expose a nearly identical behavior. In other words, this means simply that it’s possible to build a class in such a way that it will be capable of returning to client code the same output, regardless of whether the class in question works with one or with multiple objects. Sounds really interesting, isn’t it?

Naturally, in this case I’m aware of the high level of abstraction that the composite pattern intrinsically possesses, therefore over the course of these two tutorials, I’m going to demonstrate how this pattern works by setting up numerous code samples, which surely will help understand the topic more clearly.

Having introduced quickly a basic definition on the composite pattern, let’s move on and see how it can be implemented in PHP 5. The journey is going to be really educational, trust me, so let begin right now!

{mospagebreak title=Introducing the basics of the composite pattern}

In accordance with the concepts that I deployed in the beginning, you’ll certainly recall that when the composite pattern is implemented, one specific object, or a set of them, expose an identical behavior across a given application. Even though this definition seems apparently complex, it must be admitted that translating it to functional PHP code is in fact much simpler than you might think.

Therefore, I’m going to explain how this pattern works by building an abstract PHP class, which as you’ll see in a few moments, will define the generic behavior for all the child objects created from it. Logically, in accordance with the schema established by the composite pattern, one or a group of objects that belong to this class will behave similarly in the context of a PHP application.

Having said that, here is the basic structure corresponding to the aforementioned abstract class:   

// define abstract ‘FileInfoReader’ class
abstract class FileInfoReader{
   // get file info
   abstract public function getSelectedFileInfo(
$singleFileReader);
   // get number of files
   abstract public function getNumberOfFileReaders();
   // add new file
   abstract public function addFileReader($singleFileReader);
}

As you can see, all that I did above was define a simple abstract PHP class, which exposes some generic methods for retrieving information on a given file, as well as for getting and adding a few file reader objects.

Also, it’s worthwhile to mention here that you shouldn’t worry for the moment about how these objects will look, since their corresponding definition will be shown in the next section. Now, and returning to the signature of the previous abstract “FileInfoReader” class, you’ll see that it presents a special structure. It has to be the model for creating objects that will behave similarly, whether a particular application uses one or a group of them. Sounds really interesting, right?

But the question that comes up here is: how can this be achieved with PHP? Well, to be frank, the process is quite straightforward and will be limited to deriving two subclasses from the previous parent.

In this case, the first child class will define the structure of one file reader, while the second one will set up the signature for multiple file readers, in this way implementing the schema dictated by the composite design pattern.

Want to see how these brand new subclasses will be defined? Okay, go ahead and read the following section.

{mospagebreak title=Implementing the composite pattern’s model}

As I said in the section that you just read, the next step to take toward the implementation of the composite pattern will be based upon deriving two subclasses from the parent “FileInfoReader” class that you saw previously.

In this case, the first child class will be responsible for defining the behavior of only one file reader object, while the second subclass will be tasked with modeling the behavior corresponding to multiple file readers. As you’ll hopefully recall from the definition of the composite pattern, all these file reader objects must behave nearly identically.

Okay, now that I have explained how each of the aforementioned subclasses are going to work, please take a look at their respective signatures, which have been included below:

// define concrete ‘SingleFileInfoReader’ class
class SingleFileInfoReader extends FileInfoReader{
   private $fileName;
   public function __construct($fileName){
     if(!file_exists($fileName)){
       throw new Exception(‘Invalid input file!’);
     }
     $this->fileName=$fileName;
   }
   public function getSelectedFileInfo($fileReader){
     if($fileReader==1){
       return ‘Selected file has the following name: ‘.$this-
>fileName.’ and its size is: ‘.filesize($this->fileName).’
bytes’;
     }
     return false;
   }
   public function getNumberOfFileReaders(){
     return 1;
   }
   public function addFileReader($singleFileReader){
     return false;
   }
}

// define concrete ‘MultipleFileInfoReader’ class
class MultipleFileInfoReader extends FileInfoReader{
   private $fileReaders;
   public function __construct(){
     $this->fileReaders=array();
   }
   public function getSelectedFileInfo($singleFileReader){
     if($singleFileReader<=count($this->fileReaders)){
       return $this->fileReaders[$singleFileReader]-
>getSelectedFileInfo(1);
     }
     return false;
   }
   public function getNumberOfFileReaders(){
     return count($this->fileReaders);
   }
   public function addFileReader($singleFileReader){
     $this->fileReaders[]=$singleFileReader;
   }
}

As illustrated above, the two subclasses defined previously show in a clear fashion how the composite pattern works. More specifically speaking, in the first case, the “SingleFileInfoReader” class has implemented all the abstract methods declared by the respective parent in such a way that it will return to client code data corresponding to only one file reader.

With reference to the behavior exposed by the class in question, it’s clear to see here that its “getSelectedFileInfo()” method will only retrieve information about a particular file as long as the specified file reader will be equal to 1, while the other two methods will return a value of 1 and FALSE respectively. This is because the latter two methods are tasked with counting and adding new file reader objects, something not applicable in this case, so these responses are quite logical.

So far, so good. Now, having analyzed the behavior of the first subclass, please focus your attention on the second one, which is the one called “MultipleFileInfoReader.” As you can see, this class also implements concretely the same methods defined by the respective parents, which is what you expect from a concrete class.

However, the most interesting aspects with regard to the methods mentioned rest upon the way that they’ve been defined. Please notice how the first one, named “getSelectedFileInfo(),” will return to calling code data corresponding to a particular file, in this case by using only one file reader object. This implies directly that this “MultipleFileInfoReader” class behaves very similarly to “SingleFileInfoReader”.

Of course, the other two methods, that is “getNumberOfFileReaders()” and “addFileReader()” are really simple to follow and also work as expected, so I won’t spend a long time here explaining what they do.

Now are you starting to see how the two previous subclasses implement the composite pattern? I’m sure you are!

All right, at this stage you’ve hopefully grasped the logic that drives the composite pattern, thus assuming that you’ve properly understood the way that the pair of above subclasses work, it’s time to leap forward and see how they can be used together within a sample script.

Therefore, taking into account this condition, in the following section I’m going to show you how to apply the composite pattern by using the couple of child classes that you learned a few lines above.

As usual, this sample script will be built in the section to come, so click on the link below and keep reading.

{mospagebreak title=Seeing the composite pattern in action}

In order to demonstrate the functionality provided by the composite pattern, I’m going to develop a testing script, which hopefully will show that the two subclasses defined in the previous section will behave similarly, regardless of the context where they’ll be used.

Given that, and provided that there are three sample files, called “sample_file1.txt”, “sample_file2.txt” and “sample_file3.txt” respectively, whose contents are as follows:

(signature for sample_file1.txt)

This is content of sample file 1

 

(signature for sample_file2.txt)

This is content of sample file 2

 

(signature for sample_file2.txt)

This is content of sample file 3

Here is the sample script in question, which includes the corresponding outputs generated by all the prior classes. Study the following code listing, please:

try{
   $fileReader1=new SingleFileInfoReader(‘sample_file1.txt’);
   echo $fileReader1->getSelectedFileInfo(1).’<br />’;
   /*
   displays the following
   Selected file has the following name: sample_file1.txt and
its size is: 32 bytes
   */
   $fileReader2=new SingleFileInfoReader(‘sample_file2.txt’);
   echo $fileReader2->getSelectedFileInfo(1).’<br />’;
   /*
   displays the following
   Selected file has the following name: sample_file2.txt and
its size is: 32 bytes
   */
   $fileReader3=new SingleFileInfoReader(‘sample_file3.txt’);
   echo $fileReader3->getSelectedFileInfo(1).’<br />’;
   /*
   displays the following
   Selected file has the following name: sample_file3.txt and
its size is: 32 bytes
   */
   // instantiate ‘MultipleFileInfoReader’ class
   $fileReaders=new MultipleFileInfoReader();
   // add new file info reader
   $fileReaders->addFileReader($fileReader1);
   echo $fileReaders->getSelectedFileInfo($fileReaders-
>getNumberOfFileReaders()-1).’<br />’;
   /*
   displays the following
   Selected file has the following name: sample_file1.txt and
its size is: 32 bytes
   */
   // add new file info reader
   $fileReaders->addFileReader($fileReader2);
   echo $fileReaders->getSelectedFileInfo($fileReaders-
>getNumberOfFileReaders()-1).’<br />’;
   /*
   displays the following
   Selected file has the following name: sample_file2.txt and
its size is: 32 bytes
   */
   // add new file info reader
   $fileReaders->addFileReader($fileReader3);
   echo $fileReaders->getSelectedFileInfo($fileReaders-
>getNumberOfFileReaders()-1).’<br />’;
   /*
   displays the following
   Selected file has the following name: sample_file3.txt and
its size is: 32 bytes
   */
}
catch(Exception $e){
   echo $e->getMessage();
   exit();
}

As you can see, the above example clearly illustrates how the two subclasses defined before behave nearly identically, regardless of whether one or a group of file reader objects are used. This circumstance is particularly notable when using the “MultipleFileInfoReader” class, since it displays similar outputs to the ones produced by one file reader. Quite good, right?

To wrap up

In this first tutorial of the series, I introduced the basic concepts for applying the composite pattern in PHP 5. As usual with all my articles, I provided you with some examples that should give you an accurate idea of how this pattern works.

Nonetheless, this journey hasn’t ended, since in the last installment I’m going to show you how to implement this pattern along with some string handling classes. I hope to see you there!

[gp-comments width="770" linklove="off" ]
antalya escort bayan antalya escort bayan