Working with Directory Iterators and Proxy Classes with PHP 5

If you’re a strong advocate of using pattern-based programming for developing your PHP applications, then this pair of comprehensive tutorials might find a place on your quick reference list. Welcome to the concluding part of the series “Building Proxy Classes with PHP 5.” In two parts, this series introduces the foundations of how to apply the proxy pattern with PHP 5, and it accompanies the corresponding theory with extensive code samples.

Before I go deeper into the subject of this final article, let me refresh quickly the topics that I covered in the preceding article. As you’ll possibly recall, over the course of the first part of the series, I explained the core concepts related to applying the proxy design pattern in PHP 5.

However, if this pattern is still a pretty unfamiliar thing to you, allow me to explain briefly what it does. Basically, in the proxy pattern, a class (in this case, it’s called "proxy") accesses all the methods that belong to other classes. In other words, the proxy acts like an intermediate entity for a selected object, a fact that reminds one closely the behavior of different proxy servers.

So, having defined the basic logic that drives this pattern, the question is: why would we use it? Well, to be frank, the pattern can be used in those cases where you want to avoid an unnecessary instantiation of a given class, which will be used only when the application you’re working with really demands it. At first glance, this may seem like an insignificant benefit if you’re trying to boost the overall performance of your web applications, but there are times that working with many objects at the same time can bring about a notable overload on the server.

So far, so good. Assuming that the proxy pattern isn’t an unknown topic to you anymore, let me tell you what this final article is about. Since in the first part of the series I showed you how to create a proxy class for processing simple XML strings, in this installment I’m going to teach you how to create a proxy object that can be used in conjunction with the "DirectoryIterator" class that comes with PHP 5.

Does this sound interesting and educational to you? Then it’s time to learn how to couple proxy classes and iterators. Let’s get started!

{mospagebreak title=Defining the initial structure of a proxy directory class}

In consonance with the concepts that I explained in the introduction, I’m going to demonstrate how to build a generic proxy class that can be easily coupled with a directory iterator. The result of this integration will allow you develop a simple application that collects information about a selected directory via a proxy object.

Since the challenge is really appealing, let me commence by showing you the initial signature for this new proxy class. Its source code is as follows:

// define 'DirectoryProcessor' class class ProxyDirectoryProcessor{ private $dirPath; private $dirProcessor=NULL; public function __construct($dirPath='defaultPath'){ if(!is_dir($dirPath)){ throw new Exception('Invalid input directory'); } $this->dirPath=$dirPath; } // get directory path public function getPath(){ if($this->dirProcessor==NULL){ $this->createDirectoryProcessor(); } return $this->dirProcessor->getPath(); } //get size of directory entries public function getSize(){ if($this->dirProcessor==NULL){ $this->createDirectoryProcessor(); } return $this->dirProcessor->getSize(); } //get names of directory entries public function getFileNames(){ if($this->dirProcessor==NULL){ $this->createDirectoryProcessor(); } return $this->dirProcessor->getFileNames(); } }

If you’re familiar with how the proxy pattern works, then you’ll find the above class extremely easy to grasp. As you can see, the previous "ProxyDirectoryProcessor" class has some neat methods for retrieving some useful information about the entries included into a selected directory, such as their size, names and path respectively.

Also, you should noticed how the proxy class obtains all this data by using the group of methods provided by a directory processor object, which for the moment remains undefined. In addition, I’d like to stress one point that deserves special attention here: note how this directory processor isn’t instantiated by the corresponding constructor; instead, the object in question is only created when its functionality is required. Pretty neat, right?

Okay, I think that the previous proxy class now gives you a clear idea of how it works, as well as how it can be easily coupled with a directory iterator. However, the functionality offered by this class is rather limited, so let me add some extra methods to it before I proceed to define the respective director processor class that you saw before.

Do you want to see how this will be done? Please click on the link below and keep reading. 

{mospagebreak title=Improving the functionality of the proxy class}

Since the initial functionality provided by the prior "ProxyDirectoryProcessor" class is pretty limited, it would be desirable to add to it some additional methods. These will help with performing some useful tasks, such as retrieving the access timestamps that correspond to the different directory entries, as well as fetching some information concerning the respective index nodes.

Aside from all the operations that I mentioned before, it’s necessary to define another specific method. This method will be responsible for creating a directory processor object when this process will be required by the proxy class in question.

Therefore, keeping in mind all the functionality that I want to give to the proxy class, below I listed its improved signature. Have a look at it, please:

// define 'DirectoryProcessor' class class ProxyDirectoryProcessor{ private $dirPath; private $dirProcessor=NULL; public function __construct($dirPath='defaultPath'){ if(!is_dir($dirPath)){ throw new Exception('Invalid input directory');                 } $this->dirPath=$dirPath; } // get directory path public function getPath(){ if($this->dirProcessor==NULL){ $this->createDirectoryProcessor(); } return $this->dirProcessor->getPath(); } // get size of directory entries public function getSize(){ if($this->dirProcessor==NULL){ $this->createDirectoryProcessor(); } return $this->dirProcessor->getSize(); } // get names of directory entries public function getFileNames(){ if($this->dirProcessor==NULL){ $this->createDirectoryProcessor(); } return $this->dirProcessor->getFileNames(); } // get timestamps of directory entries public function getTimeStamps(){ if($this->dirProcessor==NULL){ $this->createDirectoryProcessor(); } return $this->dirProcessor->getTimeStamps(); } // get last-access timestamps of directory entries public function getLastTimeStamps(){ if($this->dirProcessor==NULL){ $this->createDirectoryProcessor(); } return $this->dirProcessor->getLastTimeStamps(); } // get last access timestamps of inodes public function getInodeLastTimeStamps(){ if($this->dirProcessor==NULL){ $this->createDirectoryProcessor(); } return $this->dirProcessor->getInodeLastTimeStamps(); } // instantiate dirProcessor object private function createDirectoryProcessor(){ $dirObj=new DirectoryProcessor($this->dirPath); $this->dirProcessor=$dirObj->getDirectoryProcessor(); } }

As you can see above, now the proxy class is capable of performing all the additional tasks that I discussed a few lines before, since I included some extra methods. Most of them deal with different types of timestamps. Besides, you’ll realize that there’s a new method called the "createDirectoryProcessor()" object, which is tasked with returning to calling code a directory processor object. That was easy, wasn’t it?

All right, at this stage, the previously defined proxy class possess some decent functionality. This functionality is logically provided by a directory processor object, according to the definition for the proxy pattern. So what’s the next step? Naturally, the next thing that I’m going to do is show you the signature for the pertinent directory processor class, in this way getting the pattern’s schema completed.

To learn how this new directory processor class will be created, please click on the link shown below and keep reading.

{mospagebreak title=Completing the proxy pattern}

As I stated in the section that you just read, in order to complete the programmatic model imposed by the proxy pattern, I need to define the signature that corresponds to the "DirectoryProcessor" class. As you just learned, this class is used by the aforementioned proxy.

Since my intention here is to demonstrate how a proxy class can be coupled with a directory iterator, the directory process that I plan to build will consist of a simple wrapper for the "DirectoryIterator" class that comes with PHP 5. It’s just as simple as it sounds.

Having said that, here is the definition for this brand new class:

// define 'DirectoryProcessor' class class DirectoryProcessor{ private $dirProcessor; public function __construct($dirPath){ if(!$this->dirProcessor=new
DirectoryIterator($dirPath)){ throw new Exception('Error instantiating
directory processor object'); } } // get path of selected directory public function getPath(){ return $this->dirProcessor->getPath(); } // get size of directory entries public function getSize(){ $output='Sizes for directory entries are as
following:<br />'; foreach($this->dirProcessor as $dirElement){ $output.='Size for current element
is :'.$dirElement->getSize().'<br />'; } return $output; } // get names of directory entries public function getFileNames(){ $output='Names for directory entries are as
following:<br />'; foreach($this->dirProcessor as $dirElement){ if($dirElement->isFile()){ $output.='Name of current file
is : '.$dirElement->getFileName().'<br />'; } } return $output; } // get timestamps of directory entries public function getTimeStamps(){ $output='Timestamps for directory entries are as
following:<br />'; foreach($this->dirProcessor as $dirElement){ if($dirElement->isFile()){ $output.='Timestamp of current file
is : '.$dirElement->getMTime().'<br />'; }                  }                  return $output; } // get last access timestamps of directory entries public function getLastTimeStamps(){ $output='Last access timestamps for directory entries
are as following:<br />'; foreach($this->dirProcessor as $dirElement){ if($dirElement->isFile()){   $output.='Last access timestamp of current
file is : '.$dirElement->getATime().'<br />';                          }                         }                         return $output;             }             // get last access timestamps of inodes             public function getInodeLastTimeStamps(){ $output='Last inode modification timestamp for
directory entries are as following:<br />'; foreach($this->dirProcessor as $dirElement){                 if($dirElement->isFile()){                 $output.='Last inode modification timestamp of current
file is :'.$dirElement->getCTime().'<br />';                  }                  } return $output; }             // get directory processor object             public function getDirectoryProcessor(){ return $this; } }

Now, definitely things are getting really interesting! As you can see, the above "DirectoryProcessor" class behaves like a simple wrapping layer for the popular "DirectoryIterator" class that you’ve used many times with your PHP 5-based applications. In this case in particular, all the functionality provided by the original proxy class is implemented concretely by the corresponding iterator.

Now that you know how the previous directory processor class looks, it’s time to jump forward and tackle the final section of the article, where I’ll be demonstrating how the pair of neat classes that I created can be integrated in a single example.

Provided that you’re interested in learning how these classes fit each other, go ahead and read the next few lines. I’ll be there, waiting for you.

{mospagebreak title=Developing a final example}

As I promised before, below I developed an illustrative example that shows how to obtain useful information about a sample "defaultPath" directory, which also contains two text files called "file1.txt" and "file2.txt" respectively. For this specific example, I listed sequentially the different values outputted when a particular method is called, so you can see more clearly how the proxy class does its business.

Here is the example in question:

try{ // instantiate 'ProxyDirectoryProcessor' object $pDirProc=new ProxyDirectoryProcessor(); // display path of selected directory echo $pDirProc->getPath(); /* displays the following: defaultPath */ // display size of directory entries echo $pDirProc->getSize(); /* displays the following: Size for directory entries are as following: Size for current element is :0 Size for current element is :0 Size for current element is :29 Size for current element is :29 */ // display names of directory entries echo $pDirProc->getFileNames(); /* displays the following: Name for directory entries are as following: Name of current file is : file1.txt Name of current file is : file2.txt */ // display timestamps of directory entries echo $pDirProc->getTimeStamps(); /* displays the following: Timestamps for directory entries are as following: Timestamp of current file is : 1160523911 Timestamp of current file is : 1160523922 */ // display last access timestamps of directory entries echo $pDirProc->getLastTimeStamps(); /* displays the following: Last access timestamps for directory entries are as following: Last access timestamp of current file is : 1160523911 Last access timestamp of current file is : 1160523922 */ // display inode timestamps of directory entries         echo $pDirProc->getInodeLastTimeStamps();         /* displays the following: Last inode modification timestamp for directory entries are
as following: Last inode modification timestamp of current file is : 1160523911 Last inode modification timestamp of current file is : 1160523922 */ } catch(Exception $e){ echo $e->getMessage(); exit(); }

After studying the above example, hopefully you’ll have a better background on how the proxy pattern works. As homework, try defining more methods for the directory processor, and for the proxy class as well. Fun is already guaranteed!

Final thoughts

In this two-part series, I introduced the key points concerning the implementation of the proxy pattern in PHP 5. As you hopefully learned, this pattern can be used when you want to avoid an unnecessary instantiation of a particular object, something that eventually can improve the overall performance of your application.

As usual, see you in the next PHP tutorial!

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

chat