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 .
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.