PHP's generators are unequivocally useful both for iteration and cooperative multi-tasking. However, the inability of generator functions to specify return values artificially limits their usefulness for multitasking in coroutine contexts. This RFC proposes the ability to both specify and access Generator return values while laying the groundwork for future sub-generator returns. The proposal is a prerequisite for the conceptually related Generator Delegation RFC .

Calling Generator::getReturn() while a generator is still valid will throw. This is consistent with the behavior seen when calling Generator::rewind() after iteration has already started. The logic behind this decision is that we should prevent calling code from mistaking a yet-to-be-computed return value ( null ) for the actual return value. This proposal's position is that invoking Generator::getReturn() on a still-valid generator (or one that has thrown) is a logic error.

Generators are particularly useful for their ability to suspend execution and resume at a later time. This capacity allows applications to cooperatively multitask discrete units of processing work. However, the inability to explicitly return values leaves coroutines in a situation where they're able to process concurrent tasks but have no standard way to access the results of those computations. Consider:

<?php $gen = function { $foo = yield myAsyncFoo ( ) ; // resume here when promised result returns $bar = yield myAsyncBar ( $foo ) ; // resume here when promised result returns // Relying on the final yield as the "return" value here is ambiguous yield $bar + 42 ; } ;

In the above code we can assume the final yield is the “return” value but this is difficult to read and further it may not be the actual intent of the generator author. Userland code can currently work around this limitation to make such “returns” more explicit using the key => value yield form:

<?php $gen = function { $foo = yield myAsyncFoo ( ) ; $bar = yield myAsyncBar ( $foo ) ; yield "return" => $bar + 42 ; } ;

The above example takes advantage of “meta data” about the yielded value in the form of the yielded key. While this approach can work to indicate intent and make code more readable it suffers from the failing that it is non-standard and concurrency frameworks are forced to fractal out their own domain-specific conventions for representing asynchronous coroutine execution results.

Generator return expressions as proposed here alleviate this problem as return statements have applicable semantics, known characteristics and low cognitive overhead: