PHP Iterables

Ma Mahalakshmi V Updated 14 Nov 2026
5 min read ·Lesson 177 of 256

What Is an Iterable?

In simple terms: An iterable is anything you can loop over with foreach: an array, a generator, or an object designed to be traversed. If a function only needs to loop over some items, it does not care whether they come from an array in memory, a generator reading a huge file, or a collection object — it just needs something iterable.

Technically: iterable is a pseudo-type, available since PHP 7.1, that accepts both arrays and objects implementing the Traversable interface (generators, Iterator, and IteratorAggregate implementations). Since PHP 8.2, iterable is formally an alias for the union type Traversable|array.

iterable
├── array
└── Traversable (interface)
    ├── Iterator            → Generator, ArrayIterator, your own iterators
    └── IteratorAggregate   → your own collection classes

Why Use iterable?

Parameter TypeAcceptsLimitation
arrayArrays onlyGenerators must be converted, loading everything into memory
TraversableObjects onlyPlain arrays are rejected
iterableBothOnly foreach (and conversion functions) can be used on it

Typing a parameter as iterable makes a function work with any source of items, including memory-efficient generators.


A Function That Accepts Any Iterable

<?php
function totalPrice(iterable $products): float
{
    $total = 0.0;

    foreach ($products as $product) {
        $total += $product['price'];
    }

    return $total;
}

function productsFromDatabase(): Generator
{
    // Simulates rows fetched one at a time
    yield ['name' => 'Desk Lamp', 'price' => 1299];
    yield ['name' => 'Backpack', 'price' => 499];
}

final class ProductCollection implements IteratorAggregate
{
    public function __construct(private array $products) {}

    public function getIterator(): Generator
    {
        yield from $this->products;
    }
}

$sources = [
    'array' => [['name' => 'Gel Pen', 'price' => 20], ['name' => 'Notebook', 'price' => 60]],
    'generator' => productsFromDatabase(),
    'ArrayIterator' => new ArrayIterator([['name' => 'Water Bottle', 'price' => 349]]),
    'collection' => new ProductCollection([['name' => 'Mouse', 'price' => 599], ['name' => 'Pad', 'price' => 150]]),
];

foreach ($sources as $label => $products) {
    printf("%-14s ₹%8.2f\n", $label, totalPrice($products));
}

Output

array          ₹   80.00
generator      ₹ 1798.00
ArrayIterator  ₹  349.00
collection     ₹  749.00

How It Works

  1. totalPrice() only uses foreach, so it can declare its parameter as iterable.
  2. It receives four very different sources: a plain array, a generator, a built-in iterator object, and a custom collection.
  3. ProductCollection implements IteratorAggregate: its getIterator() method returns a generator, which makes the object usable in foreach (see Iterators).
  4. Passing a non-iterable value (such as a string) would throw a TypeError.

Checking and Converting Iterables

<?php
var_dump(is_iterable([1, 2]));
var_dump(is_iterable(new ArrayIterator([])));
var_dump(is_iterable('text'));

function letters(): Generator
{
    yield 'a';
    yield 'b';
    yield 'c';
}

echo iterator_count(letters()) . "\n";
print_r(iterator_to_array(letters()));
print_r(iterator_to_array(['x' => 1, 'y' => 2]));   // arrays accepted since PHP 8.2

Output

bool(true)
bool(true)
bool(false)
3
Array
(
    [0] => a
    [1] => b
    [2] => c
)
Array
(
    [x] => 1
    [y] => 2
)
FunctionPurpose
is_iterable($value)Checks whether a value can be used with foreach
iterator_to_array($iterable, $preserveKeys = true)Converts any iterable to an array (arrays accepted since PHP 8.2)
iterator_count($iterable)Counts elements by iterating (arrays accepted since PHP 8.2)

Converting a generator to an array loads all values into memory and consumes the generator. Convert only when you need array features or must iterate several times.


Array Functions Need Arrays

PHP's array_* functions accept only real arrays:

<?php
function numbers(): Generator
{
    yield 1;
    yield 2;
}

try {
    array_map(fn(int $n): int => $n * 2, numbers());
} catch (TypeError $e) {
    echo $e->getMessage() . "\n";
}

Output

array_map(): Argument #2 ($array) must be of type array, Generator given

There are two solutions: convert with iterator_to_array() (simple, but loads everything), or write lazy helpers that work on any iterable.

Lazy Helpers for Iterables

<?php
function mapIterable(iterable $items, callable $fn): Generator
{
    foreach ($items as $key => $item) {
        yield $key => $fn($item);
    }
}

function filterIterable(iterable $items, callable $keep): Generator
{
    foreach ($items as $key => $item) {
        if ($keep($item)) {
            yield $key => $item;
        }
    }
}

function numbers(): Generator
{
    foreach (range(1, 10) as $n) {
        yield $n;
    }
}

$evenSquares = mapIterable(filterIterable(numbers(), fn(int $n): bool => $n % 2 === 0), fn(int $n): int => $n * $n);

echo implode(', ', iterator_to_array($evenSquares, false)) . "\n";
echo implode(', ', iterator_to_array(mapIterable(['a' => 1, 'b' => 2], fn(int $n): int => $n * 10))) . "\n";

Output

4, 16, 36, 64, 100
10, 20

The helpers accept arrays and generators, process one item at a time, and preserve keys. Libraries such as nikic/iter provide complete sets of such functions.


Returning Iterables

A function can also declare iterable as its return type. This gives the implementation freedom: it may return an array today and a generator later, without changing callers that only loop over the result:

<?php
interface ProductSource
{
    /** @return iterable<array{name: string, price: int}> */
    public function products(): iterable;
}

final class InMemoryProducts implements ProductSource
{
    public function products(): iterable
    {
        return [['name' => 'Gel Pen', 'price' => 20]];
    }
}

final class CsvProducts implements ProductSource
{
    public function __construct(private string $path) {}

    public function products(): iterable
    {
        $handle = fopen($this->path, 'r');
        fgetcsv($handle, escape: '');   // skip header

        while (($row = fgetcsv($handle, escape: '')) !== false) {
            yield ['name' => $row[0], 'price' => (int) $row[1]];
        }

        fclose($handle);
    }
}

The @return iterable<...> docblock describes the element type for IDEs and static analysis tools such as PHPStan and Psalm, because PHP itself has no generic types.

Caution: A caller that receives an iterable must not assume it can loop twice, use count(), or access elements by index — a generator supports none of these. If you need those features, require an array (or Countable) explicitly.


Common Mistakes

Using Array Functions on Iterables

Effect: TypeError when a generator or iterator object is passed.

Fix: Use foreach, lazy helpers, or iterator_to_array().

Iterating a Generator Twice

Effect: "Cannot traverse an already closed generator".

Fix: Convert to an array first, or create a new generator.

Typing Everything as array

Effect: Callers must convert generators, losing memory efficiency.

Fix: Accept iterable when the function only loops.

Losing Values With Duplicate Keys

Effect: iterator_to_array() overwrites values when keys repeat (common with yield from).

Fix: Pass false as the second argument.


Best Practices

  • Accept iterable in functions that only loop over their input.
  • Return iterable (or Generator) where lazy production of items is useful.
  • Document element types with @param and @return generics for static analysis.
  • Use lazy helpers instead of converting large iterables to arrays.
  • Require array or Countable explicitly when counting, indexing, or multiple passes are needed.

Official reference: https://www.php.net/manual/en/language.types.iterable.php

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Tutorial Index PHP Home PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope Static Variables Variable Variables PHP Echo / Print PHP printf / sprintf PHP Data Types PHP Booleans PHP NULL PHP Strings String Functions Modify Strings Concatenate Strings Slicing Strings Escape Characters String Interpolation Heredoc and Nowdoc Search in Strings Multibyte Strings PHP Floats PHP Casting PHP Type Juggling PHP Math PHP Random Numbers PHP Constants PHP Magic Constants PHP Operators Arithmetic Operators Assignment Operators Comparison Operators Increment / Decrement Operators Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence PHP If...Else...Elseif PHP If PHP If Operators PHP If...Else PHP Shorthand if PHP Nested if PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement Continue Statement PHP Functions User-defined Functions Function Arguments Default Argument Values Pass by Reference Named Arguments Variadic Functions Return Values Type Declarations in Functions Recursive Functions Variable Functions Anonymous Functions Closures Arrow Functions First-class Callable Syntax PHP Arrays Indexed Arrays Associative Arrays Create Arrays Access Array Items Update Array Items Add Array Items Remove Array Items Sorting Arrays Multidimensional Arrays Array Destructuring Array Spread Operator Search in Arrays Merge Arrays array_map / array_filter / array_reduce Array Functions PHP Superglobals $GLOBALS $_SERVER $_REQUEST $_POST $_GET $_FILES $_COOKIE $_SESSION \$\_ENV PHP RegEx RegEx Patterns RegEx Modifiers preg_match preg_replace preg_split PHP RegEx Functions PHP Form Handling PHP Form Validation PHP Form Required PHP Form URL/E-mail Form Input Sanitizing Escaping Output (htmlspecialchars) Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting DateTime Class Timezones PHP Include Include vs Require PHP File Handling PHP File Open/Read PHP File Create/Write File Delete / Rename / Copy PHP Directories PHP CSV Files PHP File Upload PHP Cookies PHP Sessions PHP Filters PHP Filters Advanced PHP Callback Functions PHP JSON PHP Exceptions Error Handling Custom Error Handler Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators PHP What is OOP PHP Classes/Objects The $this Keyword PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Destructor PHP Access Modifiers Readonly Properties PHP Inheritance Method Overriding The final Keyword PHP Class Constants PHP Abstract Classes PHP Interfaces Polymorphism PHP Traits PHP Static Methods PHP Static Properties Late Static Binding Magic Methods Object Cloning Comparing Objects Anonymous Classes PHP Enums PHP Namespaces Autoloading Classes PHP Iterables Iterators Object Serialization Strict Types Union Types Nullable Types Mixed and Never Types Nullsafe Operator PHP Attributes PHP Fibers Readonly Classes Property Hooks (PHP 8.4) Asymmetric Visibility (PHP 8.4) Reflection API SPL Data Structures MySQL Database MySQL Connect MySQL Create DB MySQL Create Table MySQL Insert Data MySQL Get Last ID MySQL Insert Multiple MySQL Prepared MySQL Select Data MySQL Where MySQL Order By MySQL Delete Data MySQL Update Data MySQL Limit Data MySQL Joins with PHP Pagination with PHP PDO Introduction PDO Connect PDO Prepared Statements PDO Fetch Modes PDO Transactions PDO Error Handling PHP XML Parsers PHP SimpleXML Parser PHP SimpleXML - Get PHP XML Expat Parser PHP DOM Parser PHP XMLReader PHP XMLWriter AJAX Intro AJAX PHP AJAX Database AJAX XML AJAX Live Search AJAX Poll AJAX with JSON Security Introduction Password Hashing SQL Injection Prevention XSS Prevention CSRF Protection Session Security Secure Cookies File Upload Security Filesystem Security Error Reporting in Production Hiding PHP Encryption with Sodium PHP Configuration (php.ini) PHP Command Line (CLI) Composer PSR-4 Autoloading Installing Extensions (PECL / PIE) Debugging PHP OPcache & Performance Garbage Collection PHP-FPM Migrating to PHP 8 Project: Contact Form with Email Project: Login & Registration System Project: CRUD App with MySQL Project: Image Upload Gallery Project: Shopping Cart with Sessions Project: Simple Blog Project: REST API with PHP
Ask about this post
AI Ask about this post

Ask questions about PHP Iterables and get answers drawn from it.

Signed-in readers only.