我不确定使用
yield
关键字时提前返回函数的正确方法是什么。
“return void”
return;
是正确的返回值吗?因为返回类型被指定为iterable
。尽管它的工作没有任何错误,但如果类型提示为 int
,则返回 void 会导致错误。那么 iterable
类型提示是否仍接受 void return 语句的异常,尽管类型提示指示应返回 iterable
的内容?
请参阅下面的示例来澄清我的问题:
class Collection
{
public $items;
}
class OrderedCollection extends Collection
{
public $orderedItems;
}
class Test
{
public function getCollectionItems(Collection $collection): iterable
{
if ($collection instanceof OrderedCollection) {
yield from $collection->orderedItems;
return; // What should I return here to early exit the function?
}
yield from $collection->items;
}
}
\Generator
或其超类型‡。生成器函数不会“返回”它们所产生的结果,如果您想这样考虑的话,它们会“返回”一个“yielder”。我相信大部分混乱源于将生成器函数称为生成器。
更好的思考方式是生成器 function outputs a
Generator
object。
所以我们有两个术语:
另一个令人困惑的方面是,我们使用 返回类型语法 来表示该函数将 输出 a
Generator
。实际上,没有任何东西可以从生成器函数中进行字面意义上的 return
编辑。生成器函数上下文中的 return;
语句更像是函数作用域的 exit;
。 (你们中的迂腐者最好不要在这次讨论中提及类似的exit(1)
价值观。🙏)
我认为这个例子很好地展示了这一切:
function test(): \Generator {
yield 'test';
return "This text vanishes into the abyss."; // return values aren't a thing
return; // instead, this "void" is the only return statement that makes sense
yield 'Execution never reaches this text.';
}
$test = test(); // this is a \Generator object
foreach($test as $item) { // \Generator objects are iterable
echo $item; // prints 'test' and nothing else
}
‡ 在您的特定情况下(将返回类型设置为
iterator
),代码工作正常,大概是因为 Generator
是某种形式的 iterator
实现。 PHP 手册和错误使用“超类型”一词来描述允许的返回类型,但我想 iterator
(我认为是子类型)也适用。
通过将这个
iterator
视为更多的“可迭代”接口,可能会更清楚生成器函数的返回类型应该是什么:您可以迭代的东西,最准确地说,是一个 Generator
对象。
琐事:
yield
语句本身使该函数成为生成器函数。这意味着,如果您在函数中的任何位置使用 yield
,无论是否执行,该函数都将被“编译”为生成器函数。 (当然,这不包括注释中的 // yield
。)这意味着生成器函数不需要声明返回类型,但一如既往,这是最佳实践。