PHP Iterables


In PHP, an iterable is a type that can be traversed using a foreach loop. Iterables are a versatile feature that allows functions, methods, and variables to accept any kind of traversable data, such as arrays or objects implementing the Traversable interface. Introduced in PHP 7.1, the iterable type provides type safety while maintaining flexibility, enabling developers to write robust, reusable, and clean code.

Iterables are especially useful in modern PHP applications, where large datasets, collections, or external libraries return objects instead of arrays. By using iterables, your code can handle both arrays and objects consistently, without depending on a specific data type.

What is an Iterable?

An iterable is any value that can be looped over with foreach. This includes:

  • Arrays – the simplest iterable.

  • Objects implementing Traversable, which include classes implementing Iterator or IteratorAggregate.

Using iterable in function parameters or return types ensures only traversable values are accepted, reducing errors caused by passing incompatible types.

Declaring Iterable Parameters

You can declare a function to accept any iterable:

function printItems(iterable $items) {
    foreach ($items as $item) {
        echo $item . "<br>";
    }
}

// Using an array
$array = [1, 2, 3];
printItems($array);

// Using an object implementing Traversable
$set = new ArrayIterator(["A", "B", "C"]);
printItems($set);

This approach allows a single function to work with multiple types of traversable data.

Iterables with Arrays

Arrays are the most common iterables:

$numbers = [10, 20, 30];

foreach ($numbers as $num) {
    echo $num . "<br>";
}

When a function accepts an iterable, it works natively with arrays, making it compatible with most existing PHP code.

Iterables with Objects

Objects can also be iterable if they implement Iterator or IteratorAggregate:

class MyCollection implements IteratorAggregate {
    private $items = [];

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

    public function getIterator(): Traversable {
        return new ArrayIterator($this->items);
    }
}

$collection = new MyCollection([100, 200, 300]);
foreach ($collection as $value) {
    echo $value . "<br>";
}

Here, MyCollection implements IteratorAggregate, which returns a Traversable object. This makes the object fully compatible with iterable type hints.

Returning Iterables from Functions

Functions can return iterables instead of arrays, improving flexibility and scalability:

function getItems(): iterable {
    return ["apple", "banana", "cherry"];
}

foreach (getItems() as $item) {
    echo $item . "<br>";
}

This ensures the function always returns traversable data, whether it is an array or an object implementing Traversable.

Using Generators as Iterables

Generators are a powerful way to create lazy iterables, allowing you to handle large datasets efficiently:

function numberGenerator(int $max): iterable {
    for ($i = 1; $i <= $max; $i++) {
        yield $i;
    }
}

foreach (numberGenerator(5) as $num) {
    echo $num . "<br>";
}

Generators combined with iterables allow processing data streams or large files without consuming large amounts of memory.

Combining Iterables and Type Safety

The iterable type ensures type safety while allowing flexibility:

function sumValues(iterable $values): int {
    $sum = 0;
    foreach ($values as $val) {
        $sum += $val;
    }
    return $sum;
}

echo sumValues([1, 2, 3]); // 6
echo sumValues(new ArrayIterator([4, 5, 6])); // 15

This prevents errors like passing a string or integer to a function expecting a traversable value.

Real-World Use Cases

  1. Database Results: Returning iterables from database queries using PDOStatement or Generator.

  2. Collections: Custom collection classes that implement IteratorAggregate for uniform iteration.

  3. File Processing: Iterating over lines in a file using generators.

  4. API Data Streams: Handling large API responses efficiently with iterable objects.

Example – iterating database rows lazily:

function fetchUsers(PDO $pdo): iterable {
    $stmt = $pdo->query("SELECT name FROM users");
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
        yield $row;
    }
}

Best Practices

  1. Use iterable type hints when a function can accept arrays or traversable objects.

  2. Avoid assuming the iterable is an array; use foreach instead of array functions.

  3. Use generators for memory-efficient iteration over large datasets.

  4. Implement IteratorAggregate in custom classes to make them iterable.

  5. Declare return type iterable for functions returning traversable data.

Common Mistakes

  • Passing non-traversable types to an iterable parameter.

  • Using array-specific functions like array_merge() on generic iterables.

  • Forgetting to implement Iterator or IteratorAggregate for custom iterable objects.

  • Returning a non-iterable value when the function specifies iterable return type.

Summary of the Tutorial

  • Iterables are any values that can be traversed with foreach, including arrays and objects implementing Traversable.

  • The iterable type hint allows functions and methods to accept multiple data types safely and flexibly.

  • Generators provide lazy evaluation, allowing large datasets to be processed efficiently.

  • Iterables make PHP code more modular, maintainable, and compatible with different data structures.

  • Using iterables properly ensures your functions are robust, type-safe, and future-proof.

Mastering iterables allows developers to write flexible, memory-efficient PHP code that can handle arrays, generators, and custom traversable objects seamlessly.


Practice Questions

  1. Write a function printItems(iterable $items) that prints each item. Test it with an array and an object implementing IteratorAggregate.

  2. Create a class MyCollection implementing IteratorAggregate that stores a list of numbers. Iterate over the object using foreach.

  3. Write a function sumIterable(iterable $numbers): int that returns the sum of all numbers in the iterable. Test it with both arrays and ArrayIterator objects.

  4. Create a generator function evenNumbers($max): iterable that yields all even numbers up to $max. Loop over it to display the values.

  5. Write a function getUsernames(iterable $users) where $users is an iterable of associative arrays with a username key. Print each username.

  6. Create a class EmployeeCollection that implements IteratorAggregate. Add several employee names and iterate over them to print each name.

  7. Write a function filterPositive(iterable $numbers): iterable that yields only positive numbers from the input iterable. Test it with a mix of positive and negative values.

  8. Create a generator function readFileLines($filename): iterable that yields each line of a file. Loop through it to print the contents.

  9. Write a function multiplyIterable(iterable $numbers, $factor) that multiplies each number in the iterable by the factor and prints the results. Test with both arrays and ArrayIterator.

  10. Create a function flatten(iterable $iterables): iterable that accepts an iterable of iterables (arrays or objects) and yields all elements as a single flat sequence.


Try a Short Quiz.

coding learning websites codepractice

No quizzes available.

Go Back Top