php iterators

PHP Iterators Part 1: Traversable, Iterable, Iterator, and Iterator Aggregate

You already iterated over a collection or array in php before using something like for loop or while loop or foreach but you haven’t heard about most advanced topic which is iterators.

 

 

Topics we will cover in this series:

 

PHP iterators is one of the advanced features that enables you to iterate over a collection like arrays but what makes it so powerful is the ability the control the iteration sequence and control the loop to move backward and forward with flexible way than the ordinary loop. PHP enables you to create a custom iterator class by implementing the iterator interface and also provides some ready to use iterators like the SPL iterators which we will demonstrate them soon in future tutorials.

 

Traversables:

php traverables and iterators

As you see in the above diagram the all iterator classes and interfaces implement the traversable interface, there are two important interfaces iterator and iteratorAggregate which we will explore them shortly in this tutorial. If you want to create a custom iterator you must implement either iterator or IteratorAggregate. First let’s describe the Traversable interface.

 

The Traversable interface used to detect if a class is traversable using foreach. It can not be used alone. Instead it must be implemented by either IteratorAggregate or Iterator

This interface has no methods, its only purpose is to be the base interface for all traversable classes.

 

One common usage of this interface is to check if an item is instance of traversable like this:

 

Iterable:

The iterable pseudo-type introduced in PHP 7.1. It accepts any array or object implementing the Traversable interface. Both of these types are iterable using foreach.

Iterable can be used as a parameter type to indicate that a function requires a set of values, but does not care about the form of the value set since it will be used with foreach

As shown in the above code we used iterable to restrict the function from accepting any arguments that are not iterable.

To check for some item that are iterable or not we can rewrite the previous example using the is_iterable() function like so:

since is_iterable() will match both traversable and array the above code is equivalent to the previous example using  Traversable interface.

 

Parameters declared as iterable may use NULL or an array as a default value.

Iterable can also be used as a return type to indicate a function will return an iterable value. If the returned value is not an array or instance of Traversable, a TypeError will be thrown.

 

The Iterator Interface:

Interface for external iterators or objects that can be iterated themselves internally. This interface used in what’s called the (Iterator Pattern). This interface extends from the Traversable interface and contain the following methods that need to be implemented:

This interface come in handy when you have an array and you want to convert it to iterator like the following example:

As you see in the above code we implemented the iterator interface and add implementations for the five methods shown above. Iterator needs an array to work with so we added a function that push a new item into the places array like this:

Then we looped over the $hillstation object as if it where an array displaying the key and the value because as we mentioned previously that iterators can be looped like arrays.

 

So why we override the five functions in the above class and what are the benefits of them. The answer is if you think about the for loop or foreach loop, in order to iterate over an array it needs to now the start element, current element, the current key, the next element, is the current element is valid. This is the same concept in iterators so you have to implement above mentioned functions.

To illustrate that this working the same as arrays let’s add a print state inside each function like this:

When you run the above code you notice the following:

  1. Before the first iteration of the loop, Iterator::rewind() is called.
  2. Before each iteration of the loop, Iterator::valid() is called. 
  3. It Iterator::valid() returns false, the loop is terminated. 
  4. If Iterator::valid() returns true, Iterator::current() and Iterator::key() are called. 
  5. The loop body is evaluated. 
  6. After each iteration of the loop, Iterator::next() is called and we repeat from step 2 above.

The loop isn't terminated until Iterator::valid() returns false or the body of the loop executes a break statement.

The only two methods that are always executed are Iterator::rewind() and Iterator::valid() (unless rewind throws an exception).

The
Iterator::next() method need not return anything. It is defined as
returning void. On the other hand, sometimes it is convenient for this
method to return something, in which case you can do so if you want.

If your iterator is doing something expensive,
like making a database query and iterating over the result set, the best
place to make the query is probably in the Iterator::rewind()
implementation.

 

Let’s see another example implementation of the Iterator interface for arrays which works with maps (key / value) pairs as well as traditional arrays:

 

The IteratorAggregate Interface:

the IteratorAggregate interface like the iterator interface, extends from traversable but unlike the Iterator interface it has only one method getIterator():

 

IteratorAggregate does the same functionality of the Iterator interface but by implementing only one method getIterator() as shown in this example:

As shown above we created an array $places and implement method getIterator() which returns ArrayIterator from the provided array. getIterator() do exactly the same logic for the five methods which we described previously in the Iterator interface.

 

Converting Iterators to Arrays:

You can easily convert an Iterator object to array using iterator_to_array() function which takes an iterator and returning array:

 

Conclusion

In this tutorial we described iterators and what their purpose, Demonstrated Traversable the base interface for iterators and the iterable data type. Also we learned about the Iterator and IteratorAggregate interfaces and how to implement them. In the next part we will describe some of the SPL iterators.

Share this: