PHP iterable type: A developer’s guide

Updated: January 10, 2024 By: Guest Contributor Post a comment

Overview

The iterable pseudo-type was introduced in PHP 7.1. It’s a valuable feature for developers that allows functions to accept both arrays and objects as input, provided that the objects are instances of Traversable, which means they can be iterated over. Understanding how to effectively use iterable helps create more flexible and robust code.

Understanding iterable

In PHP, iterable is a pseudo-type that can accept any array or object implementing the Traversable interface. Before PHP 7.1, you had to hint either array or Traversable, but iterable allows a function to accept both, providing greater flexibility.

function printValues(iterable $items) {
    foreach ($items as $item) {
        echo $item;
    }
}
printValues([1, 2, 3]); // Outputs: 123
printValues(new ArrayIterator([1, 2, 3])); // Outputs: 123

Iterating over an iterable

Using iterable, we can write a function that accepts any traversable data structure and performs an iteration.

// Define a function that uses iterable
function processIterable(iterable $data) {
    foreach ($data as $value) {
        // Process each element.
    }
}
// Use an array
processIterable([1, 2, 3, 4, 5]);
// Or use an Iterator
processIterable(new ArrayIterator([1, 2, 3, 4, 5]));

Type checking iterable

It’s also possible to verify if a variable is an iterable using the is_iterable() function. This helps in ensuring that the provided data conforms to expected types before performing operations.

$array = [1, 2, 3];
$notIterable = 123;
if (is_iterable($array)) {
    // It is iterable
}
if (!is_iterable($notIterable)) {
    // This is not iterable and will throw a TypeError if used in an iteration context.
}

Creating a custom iterable class

To create a custom object that is iterable, you typically implement the Iterator or IteratorAggregate interface. Here’s an example of implementing Iterator.

class MyIterableClass implements Iterator {
    private $items = [];
    private $index = 0;

    public function __construct($items) {
        $this->items = array_values($items);
    }

    public function current() {
        return $this->items[$this->index];
    }

    public function key() {
        return $this->index;
    }

    public function next() {
        ++$this->index;
    }

    public function rewind() {
        $this->index = 0;
    }

    public function valid() {
        return isset($this->items[$this->index]);
    }
}

$myIterable = new MyIterableClass(["a", "b", "c"]);
foreach ($myIterable as $item) {
    echo $item; // Outputs: abc
}

Iterable and Generators

Generators provide an easy way to implement simple iterators. Using yield, we can create a function that generates an iterable sequence of values without implementing any interfaces.

function generator(): iterable {
    yield 'a';
    yield 'b';
    yield 'c';
}

foreach (generator() as $value) {
    echo $value; // Outputs: abc
}

Combining iterable with other types

As of PHP 8.0, it is possible to combine iterable with another type in a union type declaration. This enhancement increases the flexibility of function parameter types even further.

function combineTypes(iterable|string $data) {
    if (is_iterable($data)) {
        foreach ($data as $item) {
            echo $item;
        }
    } else {
        echo $data;
    }
}
combineTypes(["a", "b", "c"]); // Outputs: abc
combineTypes("abc"); // Outputs: abc

Conclusion

The introduction of iterable in PHP has enabled developers to create more flexible functions and methods, especially when dealing with collections of data. By understanding and using iterable, PHP developers can write clearer and more maintainable code. It’s a feature that showcases PHP’s constant evolution towards a more robust and versatile language.