PHP 7 对 foreach 的更改:我是否仍可以删除要迭代的它们数组中的项目?

2022-08-30 16:11:21

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

这意味着您现在必须明确表示要引用现在正在迭代的数组。

但是,在示例代码中,无论如何都要引用根数组,因此无论您是否通过引用传递,它都可以正常工作。

<?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'

Vs by reference,其中我们声明是数组元素的引用:$element

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

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

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

下面是在各种版本的 PHP 上运行的此代码的演示


答案 2

推荐