Detect if PHP generator accepts send()?

Viewed 92

Is it possible to somehow detect if a generator can accept any send() command? That is, if it has any line like this:

$gen = yield;

Use-case is when generators are used to factor out side-effects (as in redux-saga). If no expression depends on the result of any side-effect, all side-effects can be run concurrently (non-blocking IO).

Did not find any useful info in the reflection API: https://www.php.net/manual/en/class.reflectiongenerator.php

Edit: In short, it should be possible to distinguish between

function gen1() {
  yield $something;
}

and

function gen2() {
  $result = yield $something;  // Accepting send()
}
1 Answers

As mentioned in the comments, and after a bit of additional digging, I'm fairly confident that what you're asking is impossible:

Let's first try to summarize how generators work:

  • When a function contains at least one yield expression, it becomes a generator function that returns a Generator instance.
  • A yield expression basically does the following:
    1. first, it updates the current value of the generator with its value (the one right after yield, or null if there is none),
    2. then, it waits until Generator::send is called on the generator (Generator::next(), which is called when iterating over a generator, is exactly the same as Generator::send(null)),
    3. when it receives a value through Generator::send, it makes the yield expression evaluate to whatever was passed as its parameter,
    4. only then, the function can resume its execution (possibly until the next yield expression).

So whether you're writing:

yield;  // same as `yield null;`

or

yield 'some value';

or

$result = yield;

or

$result = yield 'some value';

The end result is the same, the yield value simply evaluates to Generator::send's parameter. Whether you're using the result of the expression doesn't change anything as far as the generator is concerned.

In other words, it's basically like trying to know whether the return value of a function call, or a boolean expression, was stored into a variable or immediately discarded.

Related