jump to navigation

Exploring SPL : An Overview of the Iterator and IteratorAgreggate Interface January 23, 2013

Posted by Tournas Dimitrios in PHP.
trackback

My previous article (introduction to Iterators) made a short introduction about Iterators and the basic concepts of their functionality . This article , and all articles that will follow , will present practical examples as an attempt to emphasize specific features of SPL’s Iterators . Usually  Iterators transform “simple objects” (arrays or instantiated Classes)  into “looping structures” with enhanced functionality , other times , Iterators replace standard loop tasks (foreach) with its own looping capabilities (exaggerating somehow … , creating loops on steroids ) . SPL’s “Iterator part” (my definition) has a hierarchical structure  of Interfaces and Classes . Knowing the general characteristics of each “component” on the aforementioned hierarchy is crucial , as it will determine which component is best suited for our application . The graph that follows presents the hierarchical “relationship” of  all components that constitute SPLs Iterator puzzle .

SPL--inherit_graph_

This article is an overview of the Iterator and IteratorAgreggate Interface . The best approach (IMO) to describe their functionality is by using practical examples , notice through , my attempt is to demystify the basic concepts by using simplified examples . The benefits that might be gained from these techniques may not be obvious at first view , but on production (with large data-sets) , they can boost the performance of an application .

By observing the above graph , one thing is immediately evident , all Classes (and four Interfaces — Countable , OuterIterator , RecursiveIterator , SeekableIterator –) inherit their features from Iterator and IteratorAgreggate Interface . The only exception to this ,  a stand-alone Class (SplInfo) , which is used as a basis for other Classes (SplObject and DirectoryIterator)  . Classes derived from SplInfo though , inherit from Iterator all its features . Traversable Interface is the root of SPL’s Iterator puzzle , its an internal-only Abstraction Interface , so trying to implement it in  “userland” Classes will simply result in an error . We can only implement Iterator or IteratorAggregate Interface into our code .

Iterator Interface : 

Any Class that implements the Iterator Interface (and of course , defines the five functions — current , key , rewind , valid and next — )  can be used in loops and its objects are called Iterators . Actually the whole subject has been explained on my previous article , lets present the  code ones again :

<!--?<span class="hiddenSpellError" pre=""-->php
/**
 * Created by Tournas Dimitrios
 * Date: 1/20/13
 * Time: 5:16 PM
 */
// Iterator
class myIterator implements Iterator {
    private $_position = 0;
    private $_elements = array() ;

    function __construct($elements) {
    $this->_elements = $elements  ;
    $this->_position = 0;
    echo 'constructor initiated <br>' ;
    }

    function rewind() {
    echo __METHOD__;
    $this->_position = 0;
    echo '<br>' ;
    }

    function current() {
    echo __METHOD__;
    return $this->_elements[$this->_position];

    }

    function key() {
    echo '<br>' ;
    echo __METHOD__ ;
    return $this->_position;
    }

    function next() {
    echo __METHOD__;
    ++$this->_position;
    echo '<br>' ;
    }

    function valid() {
    echo __METHOD__;
    echo '<br>' ;
    return isset($this->_elements[$this->_position]);

    }
}
$elements = array(
    "firstelement",
    "secondelement",
    "lastelement",
);

$it = new myIterator($elements) ;
echo '========== Using Foreach-Loop  ===========
' ;
foreach($it as $key => $value) {
    echo '------>  ' , $key , '  :  ' , $value . '<br>'  ;
    echo '<br>----- STARTING NEXT LOOP -------<br>' ;
}
echo '========== Using For-Loop  ===========<br>' ;
for ( $it->rewind(); $it->valid(); $it->next() ) {
    $curent = $it->current() ;
    $key = $it->key() ;

}

As seen on the graph , many pre-build Classes  implement this Interface and are ready for use (no need to redefine the five functions) . Of course , nothing prevents us to write our own custom Class and to implement Iterator’s functionality in a way that suits our needs .

IteratorAggregate Interface :

This Interface is used to offload iteration tasks into another Class .  It let us reuse common Iteration from an external Class (instead of repeatedly implementing the same code inside each iterable Class) .

<?php
/**
 * Created by Tournas Dimitrios
 * Date: 1/22/13
 * Time: 21:44 PM
 */

class MyElements implements IteratorAggregate
{
    private $_items ;
    private $_count ;

    function __construct() {
     $this->_count = 0 ;
     $this->_items = array() ;
    }

// Required definition of interface IteratorAggregate
    public function getIterator() {
    return new ArrayIterator($this->_items);
    }

    public function add($value) {
    $this->_items[$this->_count++] = $value;
    return $this ;
    }
}

$elements = new MyElements();
$elements->add('firstelement')
            ->add('secondelement')
            ->add('thirdelement')
            ->add('lastelement');

foreach ($elements as $key => $val) {
    echo "My elements are : [$key -> $val]<br>";
}

To implement  the IteratorAggregate Interface into a Class , we must define a “getIterator()” function . This function must return an Iterator object , as I’m using an oversimplified example , my example just returns a build-in  ArrayIterator Class (in production code we would actually return a custom Iterator object) . Keep in mind , IteratorAggregate has no build-in Iterator functionality , its task is just to return an Iterator . Thanks to polymorphism , any Class that implements the Iteration Interface can be used as a returning object from the getIterator() function (as seen on the graph , there are many ) .

Comments»

No comments yet — be the first.

Leave a comment