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
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.
<?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.
<?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 34yield from for delegation
yield from delegates to another generator or iterable, flattening the sequence without extra boilerplate.
<?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