PHP Iterator

Alin Pintilie
5 min readFeb 6, 2023

--

If you didn’t know, yes, PHP has its own iterator functionality and if you didn’t use it you probably would be surprised to know that there are some important advantages of using it.

When it comes to parsing some data usually we are using a foreach statement applied on the array. The interesting point is that the objects could also be iterated. In fact foreach documentation says that “foreach works only on arrays and objects”.

If we iterate directly on an object by default, all visible properties will be used for the iteration. We can also modify the default behavior by making an object to implement the Traversable interface. The problem is that we can not directly implement the Traversable interface but must implement either IteratorAggregate or Iterator Interface.

The difference between them is that the IteratorAggregate is an interface that provides a way to retrieve an external iterator, while the Iterator is an interface that provides a standard way to traverse the elements of a data structure and retrieve their values and keys.

What is an iterator from a general perspective?

An iterator can be both an object and a design pattern. In this article, we are focusing on the iterator as an object but it is important to be aware of the Iterator design pattern because the are somehow related.

Here are some definitions:

An iterator is a data structure that iterates over a collection of elements to provide them, on demand, one after the other” (source : here )

An iterator is an object that allows iteration over some collection of values and maintains whatever state is necessary to keep track of the current “position” in the collection” (source : here )

An iterator is a simple kind of producer coroutine that yields a sequence of elements to a consumer coroutine. The iterator and the consumer can be viewed as separate computational processes” (source : here )

If I would give a simple definition I would say that an iterator is an object that allows us to parse the elements of a collection one after one. The iterator is not the collection.

Iterator implementation

To implement an iterator we have to implement the Iterator interface by our class. The code presented on the official page could be run here. The explanation for each method is pretty clear:

IteratorAggregate implementation

As I said above we use IteratorAggregate to retrieve an already existing iterator. This is very useful in some situations as we may see in the following sections. A class that implements IteratorAggregate must implement the getIterator function.

Code from documentation can be run here.

Useful use cases of iterator

1. Encapsulation

In our days when we are struggling to write code that does not become legacy in the next sprint and pull a request that would not be rejected after code review so is important to follow standards. Of course, each organization has its own adopted standards but still, most of them are considering OOP as a must-have. Encapsulation as you may see here stands for hiding behavior (implementation) and proprieties.

Hiding implementation

When we are working with arrays for example keys and values are exposed. Also if you are iterating over it, to do something with its value you probably will expose some implementation. This case is treated here and you can see the results below:

public function storeInvoices(Vendor $vendor, string $dateFrom, string $dateTo)
{
$invoiceIterator = new InvoiceIterator($vendor, $dateFrom, $dateTo);
foreach ($invoiceIterator as $invoice) {
$this->store($invoice);
}
}

We encapsulated the entire implementation and we can focus only on the current function purpose.

Change implementation

Another case could we when we have a collection built on top of an array but we want to change the implementation of that collection and maybe even the data structure that is built on.

We have the following case:

$invoiceCollection = new InvoiceCollection();

foreach ($invoiceCollection as $invoice) {
doSomethingWithInvoice($invoice)
}

We suppose that this is a very used snippet in our project. As we saw that there are some memory limit issues, we need to find a way to improve memory usage. The problem is that this piece of code is very often used in our project, therefore we can not afford to change each implementation.

As we can see here could be many other data structure alternatives to an array. Also if we want to have a custom implementation (like a custom object storage) we should be able to change the implementation of InvoiceCollection without affecting the pieces of code that use this collection. We can see here the proposed solution. We can even find another way to improve performance and change the only implementation of InvoiceCollection using an iterator.

However it works like an adapter pattern, the iterator is an adaptor that allows you to interact with different data structures with the same interface.

2. Improving memory usage with lazy loading

We already saw one way of optimization but the main purpose of that example was to show how we can use the iterator to hide the implementation. Now, let’s focus on probably the most popular way of improving memory allocation using the iterator. This is the case with the lazy loading approach.

As one of the above definitions says, an iterator is a way of providing elements of a collection on demand. This is the opposite of getting all elements (eager loading).

A lazy loading approach could be used when retrieving data from a database or importing from a file as you can see here. We can see in that article that results in terms of a memory consumption economy are significant (could reach 90%) and worth taking into consideration when designing a solution to a problem.

Of course, many other use cases are suitable like iterating over a directory structure or fetching data from an API but the most important aspect is understanding the mechanism behind it and choosing according to the needs.

3. Custom collection

If you are working with Laravel or other frameworks you are already familiar with PHP collections and the advantages of using them. However, if you want to understand how it is built under the hood or how to build your collection to suit your needs it is important to know something about the Iterator and IteratorAggregate. Here we have a very simple example of building our own collection.

Built in Iterators

As we now understand how iterators are working and how to build our iterator is important to not reinvent the wheel. Php already has a lot of ready-to-use iterators provided by Standard Php Library (SPL) and could be suitable for us, depending on the demands.

If this article was useful for you stay in touch for more to come.

Thank you

--

--