Generators
A PHP function that contains a yield keyword is called a "generator function".
function foo() {
	echo "hi!\n";
	yield;
	echo "working hard.\n";
	yield;
	echo "bye!\n";
}
When you call this function, it does not do anything
(it doesn't even echo "hi").
Instead, you get a Generator object,
which lets you control the execution of the function.
Let's tell PHP to start running this function:
$generator = foo();
echo "Let's start foo\n";
$generator->rewind();
echo "foo stopped\n";
You will get this output:
Let's start foo
hi!
foo stopped
The function stops when there is a yield statement.
We can tell the function to continue running using the Generator object:
$generator->send(null);
And this additional output:
working hard.
Now it stops again at the next yield.
Sending data into/out of the Generator
We can put a value behind the yield keyword to send data to the controller:
function bar() {
	yield 1;
}
$generator = bar();
$generator->rewind();
var_dump($generator->current());
int(1)
Similarly, we can send data back to the function.
If you use yield [value] as an expression,
it is resolved into the value passed in $generator->send().
function bar() {
	$receive = yield;
	var_dump($receive);
}
$generator = bar();
$generator->rewind();
$generator->send(2);
int(2)
Furthermore, the function can eventually "return" a value.
This return value is not handled the same way as a yield;
it is obtained using $generator->getReturn().
However, the return type hint must always be Generator
no matter what you return, or if you don't return:
function qux() -> Generator {
	yield 1;
	return 2;
}
Hacking generators
Sometimes we want to make a generator function that does not yield at all.
In that case, you can write 0 && yield; at the start of the function;
this will make your function a generator function, but it will not yield anything.
As of PHP 7.4.0, 0 && yield; is a no-op,
which means it will not affect your program performance
even if you run this line many times.
function emptyGenerator(): Generator {
	0 && yield;
	return 1;
}
$generator = emptyGenerator();
var_dump($generator->next());
var_dump($generator->getReturn());
NULL
int(1)