PHP Foreach通过引用传递:是否复制最后一个元素?(Bug?)[重复]

tvz2xvvm  于 2023-08-02  发布在  PHP
关注(0)|答案(5)|浏览(141)

此问题在此处已有答案

PHP Pass by reference in foreach [duplicate](9个回答)
两年前关闭。
我只是有一些非常奇怪的行为与一个简单的php脚本我写的。我把它减少到最低限度,以重新创建bug:

<?php

$arr = array("foo",
             "bar",
             "baz");

foreach ($arr as &$item) { /* do nothing by reference */ }
print_r($arr);

foreach ($arr as $item) { /* do nothing by value */ }
print_r($arr); // $arr has changed....why?

?>

字符串
该输出:

Array
(
    [0] => foo
    [1] => bar
    [2] => baz
)
Array
(
    [0] => foo
    [1] => bar
    [2] => bar
)


这是一个bug还是一些应该发生的非常奇怪的行为?

dxxyhpgq

dxxyhpgq1#

在第一个foreach循环之后,$item仍然是对$arr[2]也在使用的某个值的引用。因此,第二个循环中的每个foreach调用(不是按引用调用)都将该值替换为新值,从而将$arr[2]替换为新值。
所以循环1,值和$arr[2]变成了$arr[0],也就是'foo'。
循环2,该值与$arr[2]成为$arr[1],即'bar'。
循环3,值和$arr[2]变成$arr[2],也就是'bar'(因为循环2)。
值'baz'实际上是在第二个foreach循环的第一次调用时丢失的。

调试输出

对于循环的每次迭代,我们将回显$item的值,并递归打印数组$arr
当运行完第一个循环时,我们会看到以下输出:

foo
Array ( [0] => foo [1] => bar [2] => baz )

bar
Array ( [0] => foo [1] => bar [2] => baz )

baz
Array ( [0] => foo [1] => bar [2] => baz )

字符串
在循环结束时,$item仍然指向与$arr[2]相同的位置。
当运行完第二个循环时,我们会看到以下输出:

foo
Array ( [0] => foo [1] => bar [2] => foo )

bar
Array ( [0] => foo [1] => bar [2] => bar )

bar
Array ( [0] => foo [1] => bar [2] => bar )


您会注意到,每次数组将新值放入$item时,它也会用相同的值更新$arr[3],因为它们仍然指向相同的位置。当循环到达数组的第三个值时,它将包含值bar,因为它是由该循环的上一次迭代设置的。
这是一个bug吗?
不可以。这是指涉项目的行为,而不是Bug。它类似于运行以下内容:

for ($i = 0; $i < count($arr); $i++) { $item = $arr[$i]; }


foreach循环在本质上并不特殊,它可以忽略被引用的项。它只是简单地将变量每次设置为新值,就像在循环外一样。

vnjpjtjt

vnjpjtjt2#

$item是对$arr[2]的引用,并且被第二个foreach循环覆盖,正如animuson指出的那样。

foreach ($arr as &$item) { /* do nothing by reference */ }
print_r($arr);

unset($item); // This will fix the issue.

foreach ($arr as $item) { /* do nothing by value */ }
print_r($arr); // $arr has changed....why?

字符串

nuypyhwy

nuypyhwy3#

这是非常令人惊讶的行为,但被广泛宣布为不是一个错误。PHP(在撰写本文时)没有块级变量。如果您期望$item在退出循环时超出范围,您会发现它没有。
下面是一个简单的例子:

$arr = array('one', 'two', 'three');
foreach($arr as $item){
    echo "$item\n";
}    
echo $item;

字符串
哪些输出:

one
two
three
three


正如其他人已经说过的,您正在使用第二个循环覆盖$arr[2]中的引用变量,但这只是因为$item从未超出范围。

yizd12fk

yizd12fk4#

PHP的正确行为在我看来应该是一个NOTICE错误。如果在foreach循环中创建的引用变量在循环外使用,则应引起注意。很容易被这种行为所迷惑,当它发生时很难发现。没有开发人员会去阅读foreach文档页面,它没有帮助。
你应该在循环后unset()引用以避免这种问题。对引用使用unset()只会删除引用,而不会损害原始数据。

68bkxrlz

68bkxrlz5#

这是因为您使用了by ref指令(&)。最后一个值将被第二个循环替换,它会破坏你的数组。最简单的解决方案是为第二个循环使用不同的名称:

foreach ($arr as &$item) { ... }

foreach ($arr as $anotherItem) { ... }

字符串

相关问题