Implementing IteratorAggregate and Iterator

After a bit of a break I’m finally able to get back to writing about the predefined interfaces in PHP. PHP provides two interfaces that allow you to define how your objects behave in a foreach loop: IteratorAggregate and Iterator. Before taking a look at IteratorAggregate I’ll briefly discuss how we can iterate over objects in PHP ‘natively’ and what it means to be Traversable.

Iterating over Objects

PHP natively allows us to iterate over objects in a foreach loop. However, this only works with public properties of the object. If your object has public properties these will be the values provided in each iteration. If you’re following the concept of encapsulation in your objects though you’ll probably be using private or protected properties with getters and setters. Obviously this presents a problem if you want to iterate through the properties of the object. This is where IteratorAggregate and Iterator come in. If you implement one of these interfaces in your class you can define your own logic which governs the values to return when an object is iterated over.

On Being Traversable

Before we have a look at implementing IteratorAggregate or Iterator I should briefly mention the Traversable interface. Traversable is a bit of an oddity. The PHP manual defines it as an ‘abstract base interface that cannot be implemented alone. Instead it must be implemented by either IteratorAggregate or Iterator’. The manual goes on to explain that internal classes can implement Traversable and these can be used in a foreach construct. If Traversable is an interface that you can’t implement yourself then what good is it? You can use it in type hinting or with the instanceof operator to detect if an object can be used in a foreach construct. If you simply need to find out if you can use an object in a foreach loop and are not too worries about the exact type of the object checking if Traversable is implemented is a quick and easy solution.

Implementing IteratorAggregate

Implementing IteratorAggreagate is extremely easy. You only need to implement one method, getIterator. This method has to return a data structure that can be iterated over and the PHP engine automatically calls this method when it detects an object implementing this interface being used in a foreach loop. Of course it’s up to you whether this is an array or an object that implements the Traversable interface. A simple, contrived example of implementing this interface is as follows:


class Foo implements IteratorAggregate

{

protected $values = array();

//various methods here to work with the object and set values in $values

public function getIterator()

{

return $this->values;

}

}

IteratorAggregate is perfect for occasions when your object holds an array or Traversable object of values and all you want to do is to iterate over these. If you need to do anything more complicated, such as altering or examining values before they’re returned, you need to use it’s big brother, Iterator.

Implementing Iterator

The iterator interface is a bit more complicated that IteratorAggregate and requires that you implement five methods: current, key, next, rewind and valid. Current should return whatever the current value should be in the iteration while key should return a key value for it. Next is used to advance the Iterator forwards by one step while rewind should reset whatever pointer is being used to determine the iteration. Finally, valid should return a boolean value to indicate if a value exists for the current iteration. This seems like a lot but the PHP engine takes care of calling these methods for you at the appropriate times in a foreach loop. In most cases you’ll also find that next, rewind and valid can be pretty minimal methods. A (once again contrived) example of using Iterator is below.


class Bar implements Iterator

{

protected $values;

protected $counter = 0;

//Various methods to set data and to work with the object

public function rewind()

{

$this->counter = 0;

}

public function next()

{

$this->counter++;

}

public function valid()

{

return array_key_exists($this->counter, $this->values);

}

public function current()

{

return $this->values[$this->counter];

}

public function key()

{

return $this->counter;

}

}

This example is obviously very simple and holds no real advantages over IteratorAggregate. The true advantage of Iterator over IteratorAggregate is that it allows you to manipulate the data in key and current before it is returned. One place that I’ve done this a lot recently is in working with the SalesNet CRM API. The API returns results as XML which I process using XPath. The result of this is an array of SimpleXML elements that I can iterate over. By using Iterator for this instead of IteratorAggregate I can transform the SimpleXMLElement objects into scalar values in the current method before they’re returned. I can also have the key method return account or deal id’s for the current result. This would not be possible with IteratorAggregate. For me this was an ideal way of working with the results of a web service call in a view layer. I would usually implement the countable interface too which would be used to return the number of results held by the object. A simple call to count() would check this, followed by iteration over the object and display of the results.

I’ll post another article in this series in the next few weeks looking at using Countable, ArrayAccess and Iterator/IteratorAggregate all together in one object. I’ll also take a brief spin through the ArrayObject class and when you might want to use it.

Leave a Reply