📡 You're offline — showing cached content
New version available!
Quick Access
HTML & CSS Intermediate

PHP Generators and yield: Lazy Evaluation Explained

Master PHP generators — yield keyword, lazy evaluation, memory-efficient pipelines, yield from, and two-way communication with send().

EzyCoders Admin November 1, 2025 9 min read 2 views
PHP Generators and yield Lazy Evaluation
Share: Twitter LinkedIn WhatsApp

What Are PHP Generators?

Generators let you write functions that produce a sequence of values on demand — one at a time — without building the whole array in memory first. A generator that produces 1 million numbers uses the same memory as one that produces 10.

Your First Generator

<?php
// Regular function — builds entire array in memory
function getNumbers(int $n): array {
    $result = [];
    for ($i = 1; $i <= $n; $i++) {
        $result[] = $i;
    }
    return $result;  // allocates ALL at once
}

// Generator — produces one value at a time
function generateNumbers(int $n): Generator {
    for ($i = 1; $i <= $n; $i++) {
        yield $i;  // pause, return $i, resume next iteration
    }
}

// Usage is identical
foreach (generateNumbers(1_000_000) as $num) {
    echo $num . "\n";  // uses ~100 bytes regardless of n!
}

// Memory comparison
$arr = getNumbers(100_000);      // ~4 MB
$gen = generateNumbers(100_000); // ~200 bytes

yield Keys and Values

<?php
function csvReader(string $file): Generator {
    $handle = fopen($file, 'r');
    $headers = fgetcsv($handle);  // first row = headers

    while (($row = fgetcsv($handle)) !== false) {
        yield array_combine($headers, $row); // yields associative array
    }
    fclose($handle);
}

// Process a 10 GB CSV with constant memory
foreach (csvReader('huge_data.csv') as $row) {
    echo $row['name'] . ': ' . $row['email'] . "\n";
    // only one row in memory at a time!
}

// Yield key => value pairs
function indexedWords(array $words): Generator {
    foreach ($words as $i => $word) {
        yield $i => strtoupper($word);
    }
}

foreach (indexedWords(['php', 'js', 'python']) as $i => $word) {
    echo "$i: $word\n";
    // 0: PHP  1: JS  2: PYTHON
}

yield from — Delegating to Sub-Generators

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

function outer(): Generator {
    yield 0;
    yield from inner();  // delegates to inner generator
    yield 4;
}

foreach (outer() as $val) {
    echo $val . " ";  // 0 1 2 3 4
}

// yield from also works with arrays
function combined(): Generator {
    yield from [10, 20, 30];
    yield from range(40, 50, 10);
    yield 60;
}
// 10 20 30 40 50 60

Sending Values Into a Generator

<?php
// Generators are two-way channels — you can send data in
function accumulator(): Generator {
    $total = 0;
    while (true) {
        $value  = yield $total;  // yield sends total OUT, receives value IN
        if ($value === null) break;
        $total += $value;
    }
}

$gen = accumulator();
$gen->current();  // initialise (reach first yield)

$gen->send(10);   // send 10 in, get 10 back
$gen->send(20);   // send 20 in, get 30 back
echo $gen->send(5);  // 35

Real-World Use: Infinite Sequence

<?php
function fibonacci(): Generator {
    [$a, $b] = [0, 1];
    while (true) {
        yield $a;
        [$a, $b] = [$b, $a + $b];
    }
}

function take(Generator $gen, int $n): array {
    $result = [];
    foreach ($gen as $value) {
        $result[] = $value;
        if (count($result) >= $n) break;
    }
    return $result;
}

print_r(take(fibonacci(), 10));
// [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

Pipeline Pattern

<?php
function readLines(string $file): Generator {
    $f = fopen($file, 'r');
    while (!feof($f)) yield trim(fgets($f));
    fclose($f);
}

function filterEmpty(Generator $lines): Generator {
    foreach ($lines as $line)
        if ($line !== '') yield $line;
}

function parseJson(Generator $lines): Generator {
    foreach ($lines as $line)
        yield json_decode($line, true);
}

// Memory-efficient pipeline over huge NDJSON file
$pipeline = parseJson(filterEmpty(readLines('data.ndjson')));
foreach ($pipeline as $record) {
    processRecord($record);  // only ONE record in memory at a time
}

Q: What is the difference between a generator and an iterator?

A generator is a function that uses yield to produce values lazily. It automatically implements the Iterator interface — it has current(), next(), rewind(), valid(), and key() methods. An iterator is the interface; a generator is one specific way to implement it without writing a class.


Q: Can you rewind a generator?

No. Generators are forward-only. Calling rewind() after the generator has started throws an exception. If you need to iterate multiple times, either store results in an array or recreate the generator by calling the function again.

EzyCoders Admin
Written by
EzyCoders Admin

Team Lead and Full-Stack Developer with experience in PHP, JavaScript, SQL, DSA, and System Design. Passionate about software engineering, scalable web technologies, and helping developers prepare for coding interviews and tech careers through practical tutorials and professional guidance.

Comments (0)

No comments yet. Be the first!

Leave a Comment