为什么 'iterator_to_array' 给出的结果与 foreach 不同?
Why does 'iterator_to_array' give different results than foreach?
假设我有以下递归函数将数组转换为生成器:
function traverse(array $items): Generator {
if (!empty($items)) {
yield $items[0];
array_shift($items);
yield from traverse($items);
}
}
运行 这个函数并通过 foreach
迭代生成器给出了预期的结果:
$values = traverse(['a', 'b', 'c', 'd', 'e']);
foreach ($values as $value) {
echo $value;
}
// 'abcde' is echoed
但是,当我使用内置函数 iterator_to_array()
时,我得到以下结果:
$values = iterator_to_array(traverse(['a', 'b', 'c', 'd', 'e']));
foreach ($values as $value) {
echo $value;
}
// Only 'e' is echoed
我希望这两段代码的行为相同,但事实并非如此。为什么他们的行为不同?
我是 运行 这个 PHP 8.1.
来自the manual:
yield from does not reset the keys. It preserves the keys returned by the Traversable object, or array. Thus some values may share a common key with another yield or yield from, which, upon insertion into an array, will overwrite former values with that key.
A common case where this matters is iterator_to_array() returning a keyed array by default, leading to possibly unexpected results. iterator_to_array() has a second parameter use_keys which can be set to false to collect all the values while ignoring the keys returned by the Generator.
您的生成器每次都返回具有相同键的项目(因为它们在 array_shift
调用后被重置),因此 iterator_to_array
正在用下一个覆盖每个项目。这就是为什么您只看到返回的最后一个元素。
如果将 use_keys
参数作为 false 传递给函数,您将获得所需的行为,例如
$values = iterator_to_array(traverse(['a', 'b', 'c', 'd', 'e']), false);
假设我有以下递归函数将数组转换为生成器:
function traverse(array $items): Generator {
if (!empty($items)) {
yield $items[0];
array_shift($items);
yield from traverse($items);
}
}
运行 这个函数并通过 foreach
迭代生成器给出了预期的结果:
$values = traverse(['a', 'b', 'c', 'd', 'e']);
foreach ($values as $value) {
echo $value;
}
// 'abcde' is echoed
但是,当我使用内置函数 iterator_to_array()
时,我得到以下结果:
$values = iterator_to_array(traverse(['a', 'b', 'c', 'd', 'e']));
foreach ($values as $value) {
echo $value;
}
// Only 'e' is echoed
我希望这两段代码的行为相同,但事实并非如此。为什么他们的行为不同?
我是 运行 这个 PHP 8.1.
来自the manual:
yield from does not reset the keys. It preserves the keys returned by the Traversable object, or array. Thus some values may share a common key with another yield or yield from, which, upon insertion into an array, will overwrite former values with that key.
A common case where this matters is iterator_to_array() returning a keyed array by default, leading to possibly unexpected results. iterator_to_array() has a second parameter use_keys which can be set to false to collect all the values while ignoring the keys returned by the Generator.
您的生成器每次都返回具有相同键的项目(因为它们在 array_shift
调用后被重置),因此 iterator_to_array
正在用下一个覆盖每个项目。这就是为什么您只看到返回的最后一个元素。
如果将 use_keys
参数作为 false 传递给函数,您将获得所需的行为,例如
$values = iterator_to_array(traverse(['a', 'b', 'c', 'd', 'e']), false);