PHP
  Home arrow PHP arrow Page 2 - Building an Iterator with PHP
Dev Articles Forums 
ADO.NET  
Apache  
ASP  
ASP.NET  
C#  
C++  
ColdFusion  
COM/COM+  
Delphi-Kylix  
Design Usability  
Development Cycles  
DHTML  
Embedded Tools  
Flash  
Graphic Design  
HTML  
IIS  
Interviews  
Java  
JavaScript  
MySQL  
Oracle  
Photoshop  
PHP  
Reviews  
Ruby-on-Rails  
SQL  
SQL Server  
Style Sheets  
VB.Net  
Visual Basic  
Web Authoring  
Web Services  
Web Standards  
XML  
Mobile Linux 
App Generation ROI 
IBM® developerWorks 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us Get Paid 
Request Media Kit
Contact Us 
Site Map 
Privacy Policy 
Support 
 USERNAME
 
 PASSWORD
 
 
  >>> SIGN UP!  
  Lost Password? 
PHP

Building an Iterator with PHP
By: Dejan Bosanac
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: 4 stars4 stars4 stars4 stars4 stars / 12
    2003-08-15

    Table of Contents:
  • Building an Iterator with PHP
  • Article
  • Conclusion

  • Rate this Article: Poor Best 
      ADD THIS ARTICLE TO:
      Del.ici.ous Digg
      Blink Simpy
      Google Spurl
      Y! MyWeb Furl
    Email Me Similar Content When Posted
    Add Developer Shed Article Feed To Your Site
    Email Article To Friend
    Print Version Of Article
    PDF Version Of Article
     
     
    ADVERTISEMENT


    Building an Iterator with PHP - Article


    (Page 2 of 3 )

    Interface

    An Iterator has a very simple, and at many times, clean interface.

    <?php
    function Iterator($array) // Constructor. Takes array to be traversed as a parameter.
    function reset() // Sets internal pointer to the first element
    function end() // Sets internal pointer to the last element
    function seek($position) // Sets internal pointer to desired position
    function next() // Returns next element in the iteration
    function previous() // Returns previous element in the iteration
    ?>

    With an interface like this, you can easily perform all your daily tasks. An example would be traversing arrays in any way you want and from any position you want. One advantage of using this approach against native PHP array functions is that you have one interface for all of your array tasks. You will not use the foreach() construct for one case, list-each combination in the other and the next() and prev() functions in third any more. Another advantage is that now you can easily set the position on any particular element and start traversing from there in any way you want. Here are few code examples:

    <?php
    // $array = ?. // initialize the array
    $iterator = new Iterator($array);
    // traverse the array
    while ($elem = $iterator->next()) {
        echo $elem;
    }
    // traverse array in reverse order
    $iterator->end();
    while ($elem = $iterator->previous()) {
        echo $elem;
    }
    // traverse array from fifth element on
    $iterator->seek(5);
    while ($elem = $iterator->next()) {
        echo $elem;
    }
    ?>

    "OK" you say, "this is all nice but there is nothing I can't do with a combination of native PHP functions".

    Besides the fact that you are accessing all your arrays through a unique interface. Another and the most important advantage is that the Iterator's object structure allows you to easily expand its functionality.

    ObjectIterator Interface

    Often I have ended up in situations where my object methods returned an array of some other object as a result. Usually, that object is loaded from the database, but could be involved in some other situation such as obtaining objects through some RPC protocol (XML-RPC, SOAP, ...) or the endless amount of other situations that you may experience every day. In this article, we will focus on the first problem and briefly explain how to empower the Iterator for the purpose you will need.

    Suppose that you are developing an address book for some large web application. Your address book will work with companies and people. In addition, companies could have an endless number of employees (that are also kinds of people). So far, we have recognized two objects in our application: Company and Person. It is clear that the company will have a method called getEmployees() that returns an array of Person objects. There are a number of possible implementations of this method. Here are some usual implementations:

    First, you could write a query to collect all the ids of all the company employees. Then you could make an array that contains all the objects and returns this array. This would look something like this (supposing you have a database wrapper):

    <?php
    function getEmployees() {
    $query = "SELECT id FROM persons WHERE companyid = $this->companyid";
    $stmt = execute_query($query); // creates statement object
    $this->employees = array();
    while ($row = fetch_object($stmt) {
        $this->employess[$row->id] = new Person($row->id); // object creation
    }
    return $this->employees;
    }
    ?>

    and the usage would be:

    <?php
    $company = new Company("Datagate");
    $employees = $company->getEmployees();
    foreach ($employees as $id =>$employee)
        $employee->addVacationDays(3); // object usage
    ?>

    OK, these look like fairly obvious solutions. But, it has a few big flaws. All objects are created but we don't know if we're going to use them all. There are two performance problems here. Firstly, accessing a relational database (for creating these objects) can be very time consuming. Also, if the company has 500 employees and you need to access data for only 50, there is a lot of time wasted.

    Imagine now, that we are loading these objects through RPC, which is even slower. This could seriously affect the application's performance. Now, even if all objects are needed we don't need them at the same time. We need objects one by one as we are traversing the array. The solution above is a huge waste of resources (i.e. memory and time).

    The solution to these performance problems looks so obvious. Let's return just an array of employee ids. The code would look something like this:

    <?php
    function getEmployees() {
    $query = "SELECT id FROM persons WHERE companyid = $this->companyid";
    $stmt = execute_query($query); // creates statement object
    $this->employees = array();
    while ($row = fetch_object($stmt) {
        $this->employess[$row->id] = $row->id;
    }
    return $this->employees;
    }
    ?>

    and the usage would be:

    <?php
    $company = new Company("Datagate");
    $employees = $company->getEmployees();
    foreach ($employees as $id) {
        $employee = new Employee($id); // object creation
        $employee->addVacationDays(3); // object usage
    }
    ?>

    This looks fine at first sight. We have saved time and memory, but another problem has arisen. Suppose that the code for creating Employee object changes. For example, if you need to add an extra argument to the constructor or some extra initialization. These are things that are happening on real projects. In that case, you'll need to modify your code in many places (i.e. wherever you have used getEmployees() method). This is a problem!

    The third solution is to use an ObjectIterator class that is extended from the Iterator. In this example, you will see how easy it is to extend the Iterator class to serve your purposes. When you are using ObjectIterator, your getEmployee() function will stay the same as in the second solution. So, we have saved our resources. No unnecessary objects are created and everything looks just fine. Now let's look at the code usage:

    <?php
    $company = new Company("Datagate");
    $iterator = new Iterator($company->getEmployees(), "Employee");
    while ($employee = $iterator->next()) {
        $employee->addVacationDays(3);
    }
    ?>

    We see now that the object creation code is hidden in the ObjectIterator class, so it is now easy to support changes.

    ObjectIterator Implementation

    The code for ObjectIterator is quite simple.

    <?php
    /**
    * Implements iterator for traversing collection of objects
    * for the given array od object identifiers
    *
    * @version 1.0
    * @author <a href=mailto:chubrilo@yahoo.com>Dejan Bosanac</a>
    */
    class ObjectIterator extends Iterator {
        var $_objectName;
        /**
         * Constructor
         * Calls initialization method (@see Iterator::_initialize())
         * and do some specific configuration
         * @param array $array array of object ids to be traversed
         * @param string $objectName class of objects to be created
         * @access public
         */
        function ObjectIterator($array, $objectName) {
            $this->_initialize($array);
            $this->_objectName = $objectName;
        }
        /**
         * Returns object with given id
         * @param Object $id identifier of the object
         * @return Object next object in the collection
         * @access private
         */
        function _fetchObject($id) {
            return new $this->_objectName($id);
        }
    }
    ?>

    It has a $_objectName class member that represents the class of the object that has to be returned by the next() and previous() methods. The constructor sets this internal variable and calls an initialization function defined in Iterator class. The most important thing is the _fetchObject() function. It encapsulates code for object creation. It is called from next() and previous() methods and takes the object id as a parameter. So all of your object creation code is localized here. Thus, making it easy to change and expand.

    So, here are instructions for creating our new type of iterators. First, make your constructor, which has to have an array as a parameter that calls the _initialize() function from the Iterator class. Secondly, override the _fetchObject method to do whatever you have to do to make your objects. That would be all you need to do ;)

    More PHP Articles
    More By Dejan Bosanac


       · It's much better to use an Iterator...
     

    PHP ARTICLES

    - Making Usage Statistics in PHP
    - Installing PHP under Windows: Further Config...
    - File Version Management in PHP
    - Statistical View of Data in a Clustered Bar ...
    - Creating a Multi-File Upload Script in PHP
    - Executing Microsoft SQL Server Stored Proced...
    - Code 10x More Efficiently Using Data Access ...
    - A Few Tips for Speeding Up PHP Code
    - The Modular Web Page
    - Quick E-Commerce with PHP and PayPal
    - Regression Testing With JMeter
    - Building an Iterator with PHP
    - PHP Frontend to ImageMagick
    - Using PEAR's mimeDecode Module
    - Incoming Mail and PHP







    © 2003-2009 by Developer Shed. All rights reserved. DS Cluster 5 hosted by Hostway
    Stay green...Green IT