Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to test if a closure is also a generator?

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?

like image 229
dvlsg Avatar asked Aug 05 '14 17:08

dvlsg


2 Answers

$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

like image 101
Mark Baker Avatar answered Oct 13 '22 17:10

Mark Baker


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.

like image 3
Ihor Burlachenko Avatar answered Oct 13 '22 18:10

Ihor Burlachenko