PHP Iterables

Working with arrays and traversable objects

🔄 What are PHP Iterables?

An iterable is any value that can be looped through with a foreach loop. This includes arrays and objects that implement the Traversable interface, providing a flexible way to work with collections.


<?php
// Simple iterable example
function printItems(iterable $items) {
    foreach ($items as $item) {
        echo $item . " ";
    }
}

printItems([1, 2, 3]); // 1 2 3
?>
                                    

Why Use Iterables?

🔀

Flexibility

Accept arrays or objects in functions

Versatile Generic
✅

Type Safety

Ensure parameters can be looped

Reliable Safe
📦

Collections

Work with any collection type

Arrays Objects
🎯

Clean Code

Write more generic functions

Reusable Elegant

🔹 Basic Iterable Type Hint

The iterable type hint was introduced in PHP 7.1 and accepts both arrays and objects implementing the Traversable interface, making functions more flexible.

<?php
function displayList(iterable $items) {
    $output = "";
    foreach ($items as $item) {
        $output .= $item . "<br>";
    }
    return $output;
}

// Works with arrays
$fruits = ["Apple", "Banana", "Orange"];
echo displayList($fruits);

// Also works with iterators
$numbers = new ArrayIterator([1, 2, 3]);
echo displayList($numbers);
?>

Output:

Apple

Banana

Orange

1

2

3

🔹 Iterable Return Type

Functions can declare iterable as a return type, guaranteeing they will return something that can be looped through with foreach.

<?php
function getNumbers(): iterable {
    return [1, 2, 3, 4, 5];
}

function getColors(): iterable {
    yield "Red";
    yield "Green";
    yield "Blue";
}

// Use returned iterables
foreach (getNumbers() as $num) {
    echo $num . " ";
}
echo "<br>";

foreach (getColors() as $color) {
    echo $color . " ";
}
?>

Output:

1 2 3 4 5

Red Green Blue

🔹 Arrays as Iterables

Arrays are the most common type of iterable in PHP. They can be easily passed to functions expecting iterable parameters and looped through efficiently.

<?php
function sumValues(iterable $numbers): int {
    $total = 0;
    foreach ($numbers as $number) {
        $total += $number;
    }
    return $total;
}

function multiplyValues(iterable $numbers, int $multiplier): array {
    $result = [];
    foreach ($numbers as $number) {
        $result[] = $number * $multiplier;
    }
    return $result;
}

$values = [10, 20, 30];

echo "Sum: " . sumValues($values) . "<br>";
echo "Multiplied: " . implode(", ", multiplyValues($values, 2));
?>

Output:

Sum: 60

Multiplied: 20, 40, 60

🔹 Generators as Iterables

Generators are functions that use yield to produce values one at a time. They implement the Iterator interface automatically, making them perfect iterables for memory-efficient loops.

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

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

echo "Count to 5: ";
foreach (countTo(5) as $num) {
    echo $num . " ";
}

echo "<br>Even numbers to 10: ";
foreach (evenNumbers(10) as $num) {
    echo $num . " ";
}
?>

Output:

Count to 5: 1 2 3 4 5

Even numbers to 10: 2 4 6 8 10

🔹 Iterator Objects

PHP provides built-in iterator classes like ArrayIterator that implement the Traversable interface, allowing you to iterate over data with additional functionality.

<?php
function processIterable(iterable $data): string {
    $result = "";
    $count = 0;
    
    foreach ($data as $key => $value) {
        $count++;
        $result .= "[$key] => $value<br>";
    }
    
    return "Items: $count<br>" . $result;
}

$array = ["name" => "John", "age" => 30];
$iterator = new ArrayIterator($array);

echo processIterable($iterator);
?>

Output:

Items: 2

[name] => John

[age] => 30

🔹 Custom Iterable Class

You can create custom classes that implement the Iterator interface, making them iterable and allowing them to be used in foreach loops with custom behavior.

<?php
class NumberRange implements Iterator {
    private $start;
    private $end;
    private $current;
    
    public function __construct($start, $end) {
        $this->start = $start;
        $this->end = $end;
        $this->current = $start;
    }
    
    public function current() {
        return $this->current;
    }
    
    public function key() {
        return $this->current;
    }
    
    public function next() {
        $this->current++;
    }
    
    public function rewind() {
        $this->current = $this->start;
    }
    
    public function valid() {
        return $this->current <= $this->end;
    }
}

function showRange(iterable $range) {
    $output = "";
    foreach ($range as $num) {
        $output .= $num . " ";
    }
    return $output;
}

$range = new NumberRange(1, 5);
echo showRange($range);
?>

Output:

1 2 3 4 5

🔹 Iterable with Keys and Values

Iterables preserve both keys and values, allowing you to access associative array keys or custom keys from iterator objects during iteration.

<?php
function displayKeyValue(iterable $data): string {
    $output = "";
    foreach ($data as $key => $value) {
        $output .= "$key: $value<br>";
    }
    return $output;
}

// Associative array
$person = [
    "name" => "Alice",
    "email" => "[email protected]",
    "role" => "Developer"
];

echo displayKeyValue($person);
?>

Output:

name: Alice

email: [email protected]

role: Developer

🔹 Practical Example: Data Processing

Iterables are perfect for data processing functions that need to work with various data sources, from simple arrays to complex database result sets.

<?php
class DataProcessor {
    public static function filter(iterable $items, callable $callback): array {
        $result = [];
        foreach ($items as $item) {
            if ($callback($item)) {
                $result[] = $item;
            }
        }
        return $result;
    }
    
    public static function map(iterable $items, callable $callback): array {
        $result = [];
        foreach ($items as $item) {
            $result[] = $callback($item);
        }
        return $result;
    }
}

$numbers = [1, 2, 3, 4, 5, 6];

// Filter even numbers
$even = DataProcessor::filter($numbers, fn($n) => $n % 2 == 0);
echo "Even: " . implode(", ", $even) . "<br>";

// Double all numbers
$doubled = DataProcessor::map($numbers, fn($n) => $n * 2);
echo "Doubled: " . implode(", ", $doubled);
?>

Output:

Even: 2, 4, 6

Doubled: 2, 4, 6, 8, 10, 12

🔹 Converting Iterables to Arrays

Sometimes you need to convert an iterable to an array for operations that require array-specific functions. Use iterator_to_array() for this purpose.

<?php
function generateSquares(int $max): iterable {
    for ($i = 1; $i <= $max; $i++) {
        yield $i * $i;
    }
}

// Convert generator to array
$squares = iterator_to_array(generateSquares(5));

echo "Squares array: " . implode(", ", $squares) . "<br>";
echo "Count: " . count($squares) . "<br>";
echo "Sum: " . array_sum($squares);
?>

Output:

Squares array: 1, 4, 9, 16, 25

Count: 5

Sum: 55

🔹 When to Use Iterables

✅ Use Iterables When:

  • Writing functions that loop through data
  • You want to accept both arrays and objects
  • Building generic collection processors
  • Working with generators for memory efficiency
  • Creating flexible APIs and libraries
  • Processing database results or file streams

💡 Benefits:

  • More flexible than array type hints
  • Works with generators for lazy evaluation
  • Supports custom iterator implementations
  • Better type safety than mixed or no type hint
  • Enables memory-efficient data processing

💡 Key Points to Remember:

  • Iterables accept arrays and Traversable objects
  • Use iterable type hint for parameters and return types
  • Generators automatically implement Iterator
  • All iterables can be used in foreach loops
  • Iterables preserve keys and values
  • Convert iterables to arrays with iterator_to_array()
  • More flexible than array type hints
  • Introduced in PHP 7.1

🧠 Test Your Knowledge

Which PHP version introduced the iterable type?