PHP Iterator Pattern
A short screencast: the Iterator pattern — a uniform way to traverse a collection without exposing its internals. We iterate a bookshelf with foreach.
Overview
The Iterator provides sequential access to the elements of a collection while hiding its internal representation. The shelf itself, BookShelf, can only add books and implements IteratorAggregate, returning its iterator from getIterator(). The BookIterator keeps a position cursor and implements rewind, valid, current, next and key. The client simply writes foreach ($shelf as $book) and does not know how the collection is traversed inside — PHP calls the iterator methods itself.
UML diagram
Code
Book.php
class Book
{
public function __construct(public string $title) {}
}
BookIterator.php
class BookIterator implements Iterator
{
private int $position = 0;
public function __construct(private array $books) {}
public function current(): Book
{
return $this->books[$this->position];
}
public function key(): int
{
return $this->position;
}
public function next(): void
{
$this->position++;
}
public function rewind(): void
{
$this->position = 0;
}
public function valid(): bool
{
return isset($this->books[$this->position]);
}
}
BookShelf.php
class BookShelf implements IteratorAggregate
{
private array $books = [];
public function add(Book $book): void
{
$this->books[] = $book;
}
public function getIterator(): Iterator
{
return new BookIterator($this->books);
}
}
demo.php
require_once 'Book.php';
require_once 'BookIterator.php';
require_once 'BookShelf.php';
$shelf = new BookShelf;
$shelf->add(new Book('Refactoring'));
$shelf->add(new Book('Clean Code'));
$shelf->add(new Book('Design Patterns'));
foreach ($shelf as $book) {
echo $book->title.PHP_EOL;
}
Example output
After php demo.php the shelf iterates like a plain array, even though a custom iterator works underneath:
Refactoring
Clean Code
Design Patterns
Advantages
- The client traverses the collection uniformly and knows nothing of its internals.
- The traversal logic is separated from the collection itself.
- A single collection can offer several iterators (by order, filter, or in reverse).
foreachworks with any collection implementingIteratororIteratorAggregate.
When to use
- When you need to traverse a collection without revealing its internal structure.
- When one collection needs different traversal strategies.
- When a unified interface is required to walk different data structures.
- When you must support several simultaneous traversals of the same collection.
Usage in Laravel
In Laravel the Iterator is everywhere. The collections Illuminate\Support\Collection and Illuminate\Database\Eloquent\Collection implement IteratorAggregate, so they iterate in foreach. The query builder offers a lazy Illuminate\Support\LazyCollection, and Illuminate\Database\Eloquent\Cursor lets you stream millions of rows without loading them all into memory. The filesystem Illuminate\Filesystem\Filesystem returns a Symfony\Component\Finder\Finder, which is also an iterator over files.