PHP 7中对foreach的更改:我还能在迭代的数组中删除项目吗?

27
PHP 7不兼容变更文档 中对于foreach的说明如下:

在默认情况下,使用按值传递模式的foreach将在被迭代的数组副本上运行,而不是在数组本身上运行。这意味着在迭代过程中对数组所做的更改将不会影响到被迭代的值。

我试图理解这是什么意思,我的主要问题是这段代码在PHP 7和PHP 5.6中是否工作相同?
foreach($array as $elementKey => $element) {
    if ($element == 'x') {
        unset($array[$elementKey]);
    }
}

我的两个问题是:

  1. 这段代码还能用吗?

  2. 如果可以,你能否解释一下(例如通过实例)PHP 7 中这个新变化的含义是什么?

编辑

我一直在重新阅读文档说明。我认为它的意思是,如果你更改数组中较低位置的值,在迭代到这些项时,这些更改不会存在。例如:

$array = ['x', 'y', 'z'];

$new = [];

foreach($array as $element) {
    if ($element == 'x') {
        $array[2] = 'a';
    }

    $new[] = $element;
}

print_r($new);

然而,当我运行此示例时,PHP版本似乎没有任何区别(虽然我之前从未使用过此工具,所以不确定它的工作原理)。

我意识到如果我通过引用进行操作,那么新变量中将会有一个a。否则就不会有。但这在两个版本中都是如此。

我真正需要知道的是哪里存在不兼容性(例如)?

编辑2

@NikiC提供的答案链接给出了我寻找的剩余部分:

在大多数情况下,这种更改是透明的,除了更好的性能外,不会产生任何其他效果。但是,在数组事先是引用的情况下,有一种情况会导致不同的行为:

$array = [1, 2, 3, 4, 5];
$ref = &$array;
foreach ($array as $val) {
    var_dump($val);
    $array[2] = 0;
}
/* Old output: 1, 2, 0, 4, 5 */
/* New output: 1, 2, 3, 4, 5 */
在PHP 7中,引用数组的按值迭代不再是特例。在此情况下,没有发生复制,因此在迭代期间对数组的所有修改都将由循环反映出来。现在,每次按值迭代数组时,都会继续处理原始元素,无论循环期间进行了任何修改。本答案解释了罕见的“特殊情况”,即在版本之间的foreach操作在处理数组副本时工作方式不同的情况。
1个回答

23
只需明确表示要引用当前正在迭代的数组即可。但是,在您的示例代码中,无论是否通过引用引用根数组,它都能正常工作。
<?php
$array = ['x', 'y', 'z'];

foreach($array as $elementKey => $element) {
    if ($element=='x') {
        unset($array[$elementKey]);
    }
}

var_dump($array); // lists 'y' and 'z'

更好的例子。在这种情况下,我们在 foreach 内部改变值但没有使用引用。因此,本地更改将会丢失:

<?php
$array = ['x', 'y', 'z'];

foreach($array as $element) {
    if ($element=='x') {
        $element = 'a';
    }
}

var_dump($array); // 'x', 'y', 'z'

通过引用传递变量,我们使用$element来声明一个数组元素的引用:

<?php
$array = ['x', 'y', 'z'];

foreach($array as &$element) {
    if ($element=='x') {
        $element = 'a';
    }
}

var_dump($array); // 'a', 'y', 'z'

这里是示例代码在不同版本的 PHP 上运行的演示


2
实际上,这三个例子在5和7中的行为是相同的。 - rjdown
3
@userlite 请参考 https://dev59.com/Wmkw5IYBdhLWcg3wNX32#14854568,PHP 7章节 > 数组复制 > 第2段和后续示例。 - NikiC
1
@Machavity:你的代码示例(一旦修复为不使用数组文字,以便在旧版本的PHP上运行)在我运行它时对于所有测试版本都完全相同;如果测试使用或不使用引用语法,则在所有版本中测试也是相同的。对于所有这些PHP版本的相同代码,你看到了什么区别? - Adam Cameron
@AdamCameron 请查看NikiC的评论链接(他对PHP的理解比我好)。原来有一种情况涉及到数组是被其他东西引用并且不像你预期的那样运行。 - Machavity
2
当然,我理解这个问题。我的观点更多的是,尽管你的回答得到了很多赞同和被采纳,但我并不认为它实际上是所问问题的答案。它或许回答了一个不同的问题;-) - Adam Cameron
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接