← Back to PHP Course | Chapter 8: OOP | Lesson 13 of 14

PHP Iterator Interface

The Iterator interface teaches your own object how to be walked through step by step, like a tour guide moving from room to room. Once it knows how, a foreach loop can go through it.
Syntax
php
class ClassName implements Iterator {
    function current() { }   // value at the current position
    function key() { }
    function next() { }
    function rewind() { }
    function valid() { }     // is the position valid?
}

foreach ($object as $key => $value) { }

What Is the Iterator Interface?

PHP's built-in Iterator interface lets a custom object define exactly how it behaves inside a foreach loop, by implementing five specific methods.

Without it, foreach only works on plain arrays and objects with public properties -- Iterator lets you control iteration over any internal data structure, including ones that aren't stored as a simple array.

Example: What Is the Iterator Interface?

php
<?php
// Define the class `Numbers`, implementing `Iterator`
class Numbers implements Iterator {
    // Declare the private property `$items`, set to `[10, 20, 30]`
    private $items = [10, 20, 30];
    // Declare the private property `$pos`, set to `0`
    private $pos = 0;
    // Define the function `current` with no parameters
    function current() { return $this->items[$this->pos]; }
    // Define the function `key` with no parameters
    function key() { return $this->pos; }
    // Define the function `next` with no parameters
    function next() { $this->pos++; }
    // Define the function `rewind` with no parameters
    function rewind() { $this->pos = 0; }
    // Define the function `valid` with no parameters
    function valid() { return isset($this->items[$this->pos]); }
}
// Loop over `new Numbers()`, binding each item to `$n`
foreach (new Numbers() as $n) {
    // Print `$n . "\n"` to the output
    echo $n . "\n";
}
?>

The Five Required Methods

current() returns the value at the current position, key() returns its key, next() advances the internal pointer, rewind() resets it to the start (called once, before the first iteration), and valid() returns a boolean telling foreach whether to keep looping.

PHP calls these in a specific sequence automatically every time your object is used in a foreach.

Example: The Five Required Methods

php
<?php
// Define the class `Numbers`, implementing `Iterator`
class Numbers implements Iterator {
    // Declare the private property `$items`, set to `[10, 20]`
    private $items = [10, 20];
    // Declare the private property `$pos`, set to `0`
    private $pos = 0;
    // Define the function `current` with no parameters
    function current() { return $this->items[$this->pos]; }
    // Define the function `key` with no parameters
    function key() { return $this->pos; }
    // Define the function `next` with no parameters
    function next() { $this->pos++; }
    // Define the function `rewind` with no parameters
    function rewind() { $this->pos = 0; }
    // Define the function `valid` with no parameters
    function valid() { return isset($this->items[$this->pos]); }
}
// Create a new `Numbers` instance, stored in `$it`
$it = new Numbers();
$it->rewind();
// Keep looping while `$it->valid()` holds
while ($it->valid()) {
    echo $it->key() . ": " . $it->current() . "\n";
    $it->next();
}
?>

Implementing a Custom Iterator

A typical implementation wraps an internal array and an integer position pointer, delegating each interface method to simple operations on those two properties.

This pattern lets you add validation, lazy computation, or filtering logic inside current() or valid() that a plain array could never do.

Example: Implementing a Custom Iterator

php
<?php
// Define the class `EvenNumbers`, implementing `Iterator`
class EvenNumbers implements Iterator {
    // Declare the private property `$items`
    private $items;
    // Declare the private property `$pos`, set to `0`
    private $pos = 0;
    // Define the constructor `__construct` taking `$items`
    function __construct($items) { $this->items = $items; }
    // Define the function `current` with no parameters
    function current() { return $this->items[$this->pos]; }
    // Define the function `key` with no parameters
    function key() { return $this->pos; }
    // Define the function `next` with no parameters
    function next() { $this->pos++; }
    // Define the function `rewind` with no parameters
    function rewind() { $this->pos = 0; }
    // Define the function `valid` with no parameters
    function valid() {
        // Return `isset($this->items[$this->pos]) && $this->items[$this->pos] % 2 === 0` from this function
        return isset($this->items[$this->pos]) && $this->items[$this->pos] % 2 === 0;
    }
}
foreach (new EvenNumbers([2, 4, 6]) as $n) {
    echo $n . "\n";
}
?>

IteratorAggregate as a Shortcut

Implementing all five Iterator methods by hand is verbose when your class just wraps an existing array or object.

IteratorAggregate requires only one method, getIterator(), which returns an Iterator (often an ArrayIterator wrapping your internal data) -- PHP delegates the actual iteration to whatever you return.

Example: IteratorAggregate as a Shortcut

php
<?php
// Define the class `Collection`, implementing `IteratorAggregate`
class Collection implements IteratorAggregate {
    // Declare the private property `$items`, set to `["a", "b", "c"]`
    private $items = ["a", "b", "c"];
    // Define the function `getIterator` with no parameters
    function getIterator(): Iterator {
        // Return `new ArrayIterator($this->items)` from this function
        return new ArrayIterator($this->items);
    }
}
// Loop over `new Collection()`, binding each item to `$item`
foreach (new Collection() as $item) {
    // Print `$item . "\n"` to the output
    echo $item . "\n";
}
?>

When to Use a Custom Iterator

Custom iterators matter when the underlying data isn't a plain array -- for example, iterating over database result rows one at a time without loading them all into memory, or walking a tree/linked-list structure in a defined traversal order.

For a class that's just a thin wrapper around an array, IteratorAggregate with ArrayIterator is almost always simpler.

Example: When to Use a Custom Iterator

php
<?php
class SimpleList implements IteratorAggregate {
    private $items = [1, 2, 3];
    function getIterator(): Iterator {
        return new ArrayIterator($this->items);
    }
}
// A thin array wrapper is simpler with IteratorAggregate than a full Iterator
foreach (new SimpleList() as $item) {
    echo $item . "\n";
}
?>
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Not implementing all five methods current, key, next, rewind and valid, which causes a fatal error.
  2. Forgetting to reset the position in rewind, so a second loop finds nothing.
  3. Returning the wrong value from valid, so the loop never ends or ends immediately.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.