← Back to PHP Course | Chapter 14: Advanced PHP | Lesson 20 of 24

PHP Iterables

A function that loops over "a collection of things" often does not actually care whether that collection is a plain array or a custom object built to be looped over -- both can be walked with foreach. PHP's iterable type hint captures exactly that idea: it accepts either an array or any Traversable object, letting a function accept both without extra work.

What Counts as Iterable

Two kinds of values satisfy the iterable type: any plain PHP array, and any object that implements the built-in Traversable interface (which includes both the Iterator interface and Generator functions) -- both can be the target of a foreach loop.

Note: Think of iterable as "anything foreach can walk through", rather than trying to memorize every specific class that qualifies.

Warning: A plain object that does NOT implement Traversable, even if it holds a collection of data internally, does not satisfy the iterable type hint.

Example: What Counts as Iterable

php
<?php
function gen() {
    yield 1;
    yield 2;
}
var_dump(is_iterable([1, 2, 3]));
var_dump(is_iterable(gen()));
?>

Using iterable as a Parameter Type

Type-hinting a function parameter as iterable instead of array signals that the function will only ever loop over the input with foreach, and does not require it to specifically be a real array -- making the function usable with a wider range of inputs, including large generators.

Note: Choose iterable over array for any function that genuinely only needs to loop through its input once and never needs array-specific operations like count() or array_map().

Warning: A function hinted as iterable cannot safely call array-only functions like count(), sort(), or array_push() on its parameter, since a Generator does not support them.

Example: Using iterable as a Parameter Type

php
<?php
function printAll(iterable $items) {
    foreach ($items as $item) {
        echo $item . "\n";
    }
}
printAll([1, 2, 3]);
?>

Using iterable as a Return Type

A function can also declare its return type as iterable, signaling that it will return something loopable -- either a real array it builds up, or a generator using yield -- without committing to which specific one, giving the function's implementation flexibility to change later.

Note: Returning a generator (yield) instead of a built array can save significant memory for large datasets, since values are produced one at a time instead of all being held in memory at once.

Warning: Code calling a function with an iterable return type should not assume the result supports array functions like count() -- treat it as foreach-only unless you know the concrete type.

Example: Using iterable as a Return Type

php
<?php
function numbers(): iterable {
    yield 1;
    yield 2;
    yield 3;
}
foreach (numbers() as $n) {
    echo $n . "\n";
}
?>

The One-Time-Use Nature of Generators

Unlike an array, which can be looped over as many times as you like, a Generator can only be iterated once -- once a foreach loop over a generator finishes, looping over that same generator object again produces nothing at all, since its internal position has already advanced to the end.

Note: If a value received as iterable needs to be used more than once, convert it to a real array first with iterator_to_array(), which "materializes" a generator into a reusable array.

Warning: Looping an already-exhausted generator a second time does not raise an error -- it simply produces zero iterations, which can silently hide a bug.

Example: The One-Time-Use Nature of Generators

php
<?php
function gen() {
    yield 1;
    yield 2;
}
$g = gen();
foreach ($g as $v) { echo $v . "\n"; }
foreach ($g as $v) { echo "second pass: $v\n"; } // never runs
echo "done";
?>

iterable vs array: Choosing the Right Type Hint

Use array specifically when a function genuinely needs array-only capabilities like count(), sorting, or random access by key. Use iterable when a function only ever needs to walk through the values once with foreach -- accepting a wider range of input types at no real cost.

Note: When designing a new function, default to the narrowest type hint that still does the job -- iterable if a simple foreach loop is all you need, array if you genuinely need array-specific behavior.

Warning: Widening an existing function's parameter from array to iterable is usually a safe change; narrowing from iterable to array can break any caller currently passing in a generator.

Example: iterable vs array: Choosing the Right Type Hint

php
<?php
function countItems(array $items) {
    return count($items); // needs real array capabilities
}
function printItems(iterable $items) {
    foreach ($items as $item) {
        echo $item . "\n"; // only ever loops
    }
}
echo countItems([1, 2, 3]);
?>
Common Mistakes
  1. Assuming iterable means "array" specifically, and then calling array-only functions (like array_push()) on a parameter type-hinted as iterable, which fails if a Traversable object is passed instead.
  2. Forgetting that an iterable parameter might be a Generator, which can only be looped over once -- looping it a second time yields nothing.
  3. Type-hinting a parameter as array when iterable would be more flexible and just as safe for a function that only ever loops over its input with foreach.
Chapter Summary
  • iterable is a pseudo-type (available since PHP 7.1) representing anything that can be looped over with foreach: an array, or any object implementing Traversable.
  • A function parameter or return type hinted as iterable accepts both plain arrays and iterator/generator objects interchangeably.
  • Because a Generator can only be iterated once, code that receives an iterable should not assume it can be looped over multiple times without checking.
Browser Support

The iterable type hint has been available since PHP 7.1 and works identically on every PHP 7.1+ environment.

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.