是否有一种方法来测试闭包是否也是一个生成器


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

我正在使用一个PHP类,它需要接受多种类型的迭代器,并将它们包含在一个统一的包装器中。我需要支持(而且可以支持!)的迭代器类型之一是包含yield关键字的匿名函数——本质上是一个匿名生成器。

是否有一种方法在PHP测试是否匿名函数是一个生成器?以下是我尝试过的方法列表(旨在显示输出,而不是我如何使用它们):

$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

正如您在上面看到的,我可以调用匿名函数,然后然后确定该函数是否是可遍历的类型,但是为了以延迟加载方式实现这一点(例如,在SQL语句调用之后使用匿名函数包装每个记录的yield),我不能在foreach迭代之前调用匿名函数。

是否有任何方法/类型在PHP,我错过了,可以用来确定是否有匿名方法尚未被调用是一个生成器?

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

显示

bool(true);

INVOKED根本不显示,证明在任何时候都没有调用闭包

对于那些想知道的人来说,这个匿名函数不是生成器。它返回Generator作为其调用的结果。

根据文档:

第一次调用generator函数时,返回内部generator类的对象。