Iterator Pattern in Zend Framework

The Iterator design pattern has provided a common mechanism for accessing collections. It allow user to traversal, access, and manipulate data sets, such as array, files, RSS feeds and database result sets etc., in the same way.

 

One of the progresses which php5 compare to php4 is that it encapsulates a variety of iterator interface. It’s just so easy to implements the iterator in php5.

 

There are plenty of examples that implement the iterator in Zend Framework. Now let’s take Zend_Feed for example :

 

 

The source code below is simplified and first of all is Zend_Feed_Element : 

 

/**
 * Zend_Feed_Element for encapsulating DOMElement
 */

class Zend_Feed_Element implements ArrayAccess
{
    // @var DOMElement DOM object
    protected $_element;

    // Zend_Feed_Element construct
    public function __construct($element = null)
    {
        $this->_element = $element;
    }

    // ......

    /**
     * ArrayAccess interface function
     * Check element exists or not
     */

    public function offsetExists($offset)
    {
        // ......
        return $this->_element->hasAttribute($offset);
    }

    /**
     * ArrayAccess interface function
     * Return attribute of element
     */

    public function offsetGet($offset)
    {
        // ......
        return $this->_element->getAttribute($offset);
    }

    /**
     * ArrayAccess interface function
     * Return the value of element
     */

    public function offsetSet($offset, $value)
    {
        // ......
        return $this->_element->setAttribute($offset, $value);
    }

    /**
     * ArrayAccess interface function
     * Unset the attribute of element
     */

    public function offsetUnset($offset)
    {
        // ......
        return $this->_element->removeAttribute($offset);
    }

    // ......
}

 

We notice that Zend_Feed_Element has implemented ArrayAccess interface which means we can maniplate Zend_Feed_Element and its children as array.

 

Then is abstract parent Zend_Feed_Abstract : 

 

require_once 'Zend/Feed/Element.php';

/**
 * Zend_Feed_Abstract the abstract parent for feeds
 * It has implemented two core interfaces from php5 : ArrayAccess and Iterator
 */

abstract class Zend_Feed_Abstract extends Zend_Feed_Element implements Iterator
{
    /**
     * Index of current entries
     * It's used for iterator
     * @var integer
     */

    protected $_entryIndex = 0;

    /**
     * Entries data sets
     * @var array
     */

    protected $_entries;

    // ......

    // Iterator interface method, rewind index
    public function rewind()
    {
        $this->_entryIndex = 0;
    }

    // Iterator interface method, return current entry
    public function current()
    {
        return new $this->_entryClassName(
            null,
            $this->_entries[$this->_entryIndex]);
    }

    // Iterator interface method, return index of current entry
    public function key()
    {
        return $this->_entryIndex;
    }

    // Iterator interface method, set next index
    public function next()
    {
        ++$this->_entryIndex;
    }

    // Iterator interface method, validate the current index
    public function valid()
    {
        return 0 <= $this->_entryIndex && $this->_entryIndex < $this->count();
    }

    // ......
}

 

Zend_Feed_Abstract has implemented ArrayAccess and Iterator interface, which means we can now access the data sets inherited from Zend_Feed_Abstract just like accessing array.

 

Here are two children, Zend_Feed_Rss and Zend_Feed_Atom :

 

require_once 'Zend/Feed/Abstract.php';

class Zend_Feed_Rss extends Zend_Feed_Abstract
{
    // ......
}

class Zend_Feed_Atom extends Zend_Feed_Abstract
{
    // ......
}

 

Examples of how they act :

 

$channel = new Zend_Feed_Rss('http://rss.example.com/channelName');
foreach ($channel as $item) {
    echo 'Title: ' . $item->title() . "n";
}

$feed = new Zend_Feed_Atom('http://atom.example.com/feed/');
foreach ($feed as $entry) {
    echo 'Title: ' . $entry->title() . "n";
}

 

The Iterator has provided a common and unified method for accessing data sets in our applications. It abstracts out the concept of accessing data collections and transparents these kind of operations to users.

 

Thanks to iterator, we can focus on business logic and improve the efficiency of development.

 

Posted in Design Patterns | Tagged , | 1 Comment