有没有办法测试一个闭包是否也是一个发电机?

时间:2014-08-05 17:34:07

标签: php closures generator yield

我正在使用一个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中是否有任何方法/类型可用于确定尚未调用 not 的匿名方法是否为生成器?

2 个答案:

答案 0 :(得分:18)

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

显示

bool(true);
根本没有显示

INVOKED,证明任何时候都没有调用闭包

答案 1 :(得分:3)

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

根据the docs

  

第一次调用生成器函数时,将返回内部Generator类的对象。