yield
The yield keyword is used in PHP to create a generator function. A generator is a special kind of function that can be paused and resumed during execution,
Introduction
The yield keyword turns an ordinary PHP function into a generator — a function that produces a sequence of values one at a time, pausing after each value and resuming where it left off when the next value is requested. This page covers how yield works, how to yield keys, how to send values back into a generator, the yield from delegation syntax, and when generators save memory compared with building a full array.
A function becomes a generator the moment it contains at least one yield. Calling it does not run the body — it returns a Generator object. The body runs only as you iterate, advancing to the next yield each step. Because a generator implements the Iterator interface, you usually consume it with a foreach loop.
A first generator
Each yield hands one value to the caller and freezes the function until the next value is asked for.
myGenerator() returns a generator object instead of running immediately. The foreach loop pulls values out of it: on each pass the function runs up to the next yield, emits that value, and pauses. The output is:
Hello World !Unlike a function that builds and returns an array, all three strings are never held in memory at the same time — each is produced on demand. Compare this with how a normal function uses return to send back a single value and exit.
Yielding keys
A generator can yield key/value pairs with the yield $key => $value syntax, exactly like an associative array. The keys are available inside foreach:
<?php
function settings()
{
yield "host" => "localhost";
yield "port" => 5432;
yield "user" => "admin";
}
foreach (settings() as $key => $value) {
echo "$key = $value\n";
}Output:
host = localhost
port = 5432
user = adminIf you don't supply keys, PHP auto-numbers yielded values starting at 0, just like an indexed array.
Generators are lazy: a memory-friendly range
The real benefit of yield is that values are computed only when needed. A generator that produces a million numbers uses constant memory, while an array of a million numbers allocates all of them up front.
<?php
function gen_range($start, $end)
{
for ($i = $start; $i <= $end; $i++) {
yield $i;
}
}
$sum = 0;
foreach (gen_range(1, 1000000) as $n) {
$sum += $n;
}
echo $sum;Output:
500000500000The loop never builds a [1, 2, …, 1000000] array; only one integer exists at a time. This is the pattern to reach for when reading huge files line by line or streaming database rows.
Returning a value from a generator
A generator may also use return to expose a final value (PHP 7+). The return value is not part of the iteration — you read it afterwards with getReturn():
<?php
function counter()
{
yield 1;
yield 2;
return "done";
}
$gen = counter();
foreach ($gen as $value) {
echo $value . " ";
}
echo $gen->getReturn();Output:
1 2 doneCalling getReturn() before the generator has finished iterating throws an exception, so always exhaust it first.
Sending values in with send()
Generators are two-way: a yield expression can also receive a value sent from the caller via send(). This is the basis of coroutines.
<?php
function echoTimes()
{
while (true) {
$received = yield;
echo "Got: $received\n";
}
}
$gen = echoTimes();
$gen->current(); // prime the generator (run up to the first yield)
$gen->send("a");
$gen->send("b");Output:
Got: a
Got: bsend($value) resumes the generator, making the paused yield expression evaluate to $value, then runs to the next yield.
Delegating with yield from
yield from (PHP 7+) yields every value from another generator, array, or Traversable, flattening it into the current one without a manual loop:
<?php
function inner()
{
yield 2;
yield 3;
}
function outer()
{
yield 1;
yield from inner();
yield from [4, 5];
}
foreach (outer() as $value) {
echo $value . " ";
}Output:
1 2 3 4 5 When to use a generator
- Large or unbounded sequences — reading a multi-gigabyte file or an infinite stream where holding everything in an array is impossible.
- Expensive values you may not need — if the consumer might stop early (
break), a generator avoids computing the rest. - Cleaner iteration code — replacing a custom
Iteratorclass with a single function.
Avoid generators when you need random access ($arr[42]), to count() results cheaply, or to iterate the same data multiple times — a generator can only be traversed once. For those cases, build a normal array, possibly with PHP functions like array_map.