我有一个方法,它采用一个生成器加上一些额外的参数,并产生一个新的生成器:
function merge(\Generator $carry, array $additional)
{
foreach ( $carry as $item ) {
yield $item;
}
foreach ( $additional as $item ) {
yield $item;
}
}
此函数的常用用例与此类似:
function source()
{
for ( $i = 0; $i < 3; $i++ ) {
yield $i;
}
}
foreach ( merge(source(), [4, 5]) as $item ) {
var_dump($item);
}
但问题是,有时我需要将空源传递给merge
方法。理想情况下,我希望能够做到这样的事情:
merge(\Generator::getEmpty(), [4, 5]);
这正是我在C#中所做的事情(有一个IEnumerable<T>.Empty
属性)。但我没有看到任何一种empty
发电机in the manual。
我已经设法使用此函数解决此问题(现在):
function sourceEmpty()
{
if ( false ) {
yield;
}
}
这很有效。代码:
foreach ( merge(sourceEmpty(), [4, 5]) as $item ) {
var_dump($item);
}
正确输出:
int(4)
int(5)
但这显然不是一个理想的解决方案。将空生成器传递给merge
方法的正确方法是什么?
有点迟了,但自己需要一个空发电机,并意识到创建一个实际上很容易......
function empty_generator(): Generator
{
yield from [];
}
不知道这是否比使用EmptyIterator
更好,但这样你至少可以获得与非空生成器完全相同的类型。
我找到了解决方案:
由于\Generator
扩展\Iterator
我可以将方法签名更改为:
function merge(\Iterator $carry, array $additional)
{
// ...
这是输入协方差,因此它会破坏向后兼容性,但前提是有人确实扩展了merge
方法。任何调用仍然有效。
现在我可以使用PHP的本机EmtpyIterator
调用该方法:
merge(new \EmptyIterator, [4, 5]);
通常的发电机也有效:
merge(source(), [4, 5])
只是为了完整性,或许到目前为止最简单的答案:
function generator() {
return; yield;
}
我只是想知道同样的问题,并记得文档中的早期描述(至少应该在语义上直到今天)生成器函数是yield
关键字的任何函数。
现在当函数在它产生之前返回时,生成器应该为空。
就是这样。
3v4l.org上的示例:https://3v4l.org/iqaIY
如the official docs中所述,您可以通过在表达式中使用Generator
来创建内联yield
实例:
$empty = (yield);
这应该工作,但是当我尝试使用它时,我得到一个致命的错误(yield
表达式只能在函数中使用)。使用null
也无济于事:
$empty = (yield null); //error
所以我猜你是坚持使用sourceEmpty
函数......这是我发现的唯一有效的东西......注意它会在你迭代的数组中创建一个null
值。
所有代码都在PHP 5.5.9,BTW上进行了测试
我能想到的最好的解决方案(看作兼容性是个问题)就是让两个参数都是可选的:
function merge(\Generator $carry = null, array $additional = array())
{
if ($carry)
foreach ($carry as $item)
yield $item;
foreach ($additional as $item)
yield $item;
}
foreach(merge(null, [1,2]) as $item)
var_dump($item);
这样,现有的代码不会制动,而不是构造一个空的生成器,传递null
也会正常工作。