Generators in Depth
Generator delegation lets one generator hand its walk over to another generator. Values sent in and values returned can also travel through a generator.
yield from delegates the walk
The outer generator hands its walk to the inner one. The inner values print first, and then the outer value prints.
<?php
function inner() {
yield 1;
yield 2;
}
function outer() {
yield from inner();
yield 3;
}
foreach (outer() as $n) {
echo $n, "\n";
}Return values travel back through the delegation
The inner generator returns a note after its last yield, and the outer generator reads it from the yield from line. After the walk, getReturn prints what the outer generator returned.
<?php
function inner() {
yield 1;
yield 2;
return "inner done";
}
function outer() {
$note = yield from inner();
echo $note, "\n";
yield 3;
return "outer done";
}
$gen = outer();
foreach ($gen as $n) {
echo $n, "\n";
}
echo $gen->getReturn(), "\n";send pushes a value into the paused yield
current reads the first yield without moving past it. send then hands a word in, and it returns the next yielded value.
<?php
function echoBox() {
$word = yield "ready";
echo "got ", $word, "\n";
yield "sent back";
}
$gen = echoBox();
echo $gen->current(), "\n";
echo $gen->send("hello"), "\n";Example
<?php
function page($items) {
$total = 0;
foreach ($items as $item) {
$total = $total + $item;
yield $item;
}
return $total;
}
function reader() {
$first = yield from page([10, 20]);
$second = yield from page([5, 5]);
return $first + $second;
}
$stream = reader();
foreach ($stream as $n) {
echo $n, "\n";
}
echo $stream->getReturn(), "\n";Key points
- yield from hands the walk to another generator until that generator ends.
- The inner return value becomes the value of the yield from line.
- getReturn reads the return value of a generator after its walk has finished.
- send pushes a value into the paused yield and resumes the walk.
- Inside the generator, the yield line takes the value that was sent in.
In this example, page yields each item while it adds a running total. The page hands that total back as its return value. reader delegates to two pages in turn and adds both returned totals. The walk prints the four items in order, and getReturn prints the combined total of 40.
Note
send returns a value too, namely the next value the generator yields.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What does send("hello") do to a generator paused at a yield?