Generators and yield

A generator produces values one at a time with yield, so you can iterate huge or infinite sequences without holding them all in memory.

A function that contains yield is a generator. Calling it doesn't run the body — it hands back an iterator. Each time you pull a value, the function runs up to the next yield, produces that value, then pauses, keeping all its local state. This is lazy evaluation: you compute values only as they're consumed.

Easy example

<?php
function countTo(int $n) {
    for ($i = 1; $i <= $n; $i++) {
        yield $i;
    }
}
foreach (countTo(3) as $v) {
    echo $v; // 123
}

The payoff is memory. Reading a million-line file line by line with a generator uses a constant amount of RAM; building an array of a million lines does not. You can also yield $key => $value pairs.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Stream a large CSV file line by line with a generator so only one row is held in memory at a time.
  • Generate an infinite Fibonacci sequence lazily with yield and pull only as many values as needed.
  • Use yield from to delegate to a sub-generator when composing a paginated API response iterator.

More examples

Yielding a large file line by line

yield pauses execution and returns one value; the loop resumes the generator on each iteration without loading the file at once.

Example · php
<?php
function readLines(string $path): \Generator {
    $fh = fopen($path, 'r');
    while (($line = fgets($fh)) !== false) {
        yield trim($line);
    }
    fclose($fh);
}

// Only one line lives in memory at a time
foreach (readLines('/etc/hostname') as $line) {
    echo $line . "\n";
}

Infinite sequence with yield

A generator can loop infinitely; the caller controls how many values it consumes by calling next() or using foreach.

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

$gen = fibonacci();
for ($i = 0; $i < 10; $i++) {
    echo $gen->current() . ' ';
    $gen->next();
}
// 0 1 1 2 3 5 8 13 21 34

yield from for delegation

yield from delegates to another generator or iterable, flattening the sequence without extra boilerplate.

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

function outer(): \Generator {
    yield 0;
    yield from inner();
    yield 4;
}

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

Discussion

  • Be the first to comment on this lesson.