Iterator Design Pattern in PHP

1. Definition

The Iterator Design Pattern provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation. It decouples the collection from the code that uses it, allowing for different types of collections to be traversed uniformly.

2. Problem Statement

Imagine having a collection of items and needing a consistent way to loop through them. Using arrays might be straightforward, but what if we have different types of collections, like linked lists or trees? We need a unified interface to iterate through all these collections without knowing their internal structures.

3. Solution

The Iterator pattern introduces a standard way to traverse collections through an Iterator interface. The actual traversal details are encapsulated in concrete Iterator implementations for each collection type.

4. Real-World Use Cases

1. Traversing through a playlist of songs.

2. Navigating through pages of a book.

3. Iterating over rows in a database result set.

5. Implementation Steps

1. Define an Iterator interface that declares traversal methods.

2. Implement concrete Iterators for different collections.

3. The collections themselves should provide a method to return their iterator.

6. Implementation in PHP

<?php
// Iterator Interface
interface IteratorInterface {
    public function hasNext(): bool;
    public function next();
}
// Concrete Iterator
class ArrayIterator implements IteratorInterface {
    private $items;
    private $index = 0;
    public function __construct(array $items) {
        $this->items = $items;
    }
    public function hasNext(): bool {
        return isset($this->items[$this->index]);
    }
    public function next() {
        return $this->items[$this->index++];
    }
}
// Aggregate Interface
interface Aggregate {
    public function getIterator(): IteratorInterface;
}
// Concrete Aggregate
class ArrayCollection implements Aggregate {
    private $items;
    public function __construct(array $items) {
        $this->items = $items;
    }
    public function getIterator(): IteratorInterface {
        return new ArrayIterator($this->items);
    }
}
// Client Code
$collection = new ArrayCollection(['A', 'B', 'C']);
$iterator = $collection->getIterator();
while ($iterator->hasNext()) {
    echo $iterator->next() . ' ';
}
?>

Output:

A B C

Explanation:

1. IteratorInterface: This is the main interface that provides traversal methods.

2. ArrayIterator: A concrete iterator for arrays. It implements the traversal logic for arrays.

3. Aggregate: An interface that returns an iterator. Every collection should implement this.

4. ArrayCollection: A concrete collection for arrays that returns its specific iterator.

5. The client code doesn't need to know about the internal structure of the ArrayCollection. It just uses the iterator to loop through the items.

7. When to use?

Use the Iterator pattern when:

1. You want to provide a uniform traversal interface for different collections.

2. You want to decouple your code from the internal structure of collections.

3. You want to introduce new types of collections without changing the client code.


Comments