18

I am working with a PHP class which needs to accept multiple types of iterators and encompass them inside a unified wrapper. One of the types of iterators I need to support (and can!) is an anonymous function containing the yield keyword -- an anonymous generator, essentially.

Is there a way in PHP to test whether or not an anonymous function is a generator? The following is a list of methods I have tried (designed to show the outputs, not how I used them):

$anon = function() { yield 1; yield 2; };   // build anonymous generator
gettype($anon);                             // "object"
$anon instanceof \Traversable;              // 0
$anon instanceof \Iterable;                 // 0
$anon instanceof \IteratorAggregate;        // 0
$anon instanceof \Generator;                // 0
$anon instanceof \Closure;                  // 1 -- but doesn't tell me whether or not the closure is actually generator

$anon = $anon();                            // invoke, then run the same checks
gettype($anon);                             // "object"
$anon instanceof \Traversable;              // 1 (!!!)
$anon instanceof \Iterable;                 // 0
$anon instanceof \IteratorAggregate;        // 0
$anon instanceof \Generator;                // 1 (!!!)
$anon instanceof \Closure;                  // 0

As you can see above, I can invoke the anonymous function and then determine whether or not the function is a traversable type, but in order to implement this in a lazy-loading fashion (for example, an anonymous function wrapper around a SQL statement call followed by a yield of each record), I cannot invoke the anonymous function before the foreach iteration.

Are there any methods / types in PHP which I am missing that can be used to determine whether or not an anonymous method which has not yet been invoked is a generator?

dvlsg
  • 5,378
  • 2
  • 29
  • 34

2 Answers2

19
$anon = function() { echo 'INVOKED', PHP_EOL; yield 1; yield 2; };
$r = new ReflectionFunction($anon);
var_dump($r->isGenerator());

shows

bool(true);

INVOKED isn't displayed at all, proving that the closure isn't invoked at any time

Mark Baker
  • 209,507
  • 32
  • 346
  • 385
3

For those who are wondering, that anonymous function is not a Generator. It returns Generator as result of its invocation.

According to the docs:

When a generator function is called for the first time, an object of the internal Generator class is returned.

Ihor Burlachenko
  • 4,689
  • 1
  • 26
  • 25