此问题在此处已有答案:
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还是一些应该发生的非常奇怪的行为?
5条答案
按热度按时间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
。当运行完第一个循环时,我们会看到以下输出:
字符串
在循环结束时,
$item
仍然指向与$arr[2]
相同的位置。当运行完第二个循环时,我们会看到以下输出:
型
您会注意到,每次数组将新值放入
$item
时,它也会用相同的值更新$arr[3]
,因为它们仍然指向相同的位置。当循环到达数组的第三个值时,它将包含值bar
,因为它是由该循环的上一次迭代设置的。这是一个bug吗?
不可以。这是指涉项目的行为,而不是Bug。它类似于运行以下内容:
型
foreach循环在本质上并不特殊,它可以忽略被引用的项。它只是简单地将变量每次设置为新值,就像在循环外一样。
vnjpjtjt2#
$item
是对$arr[2]
的引用,并且被第二个foreach循环覆盖,正如animuson指出的那样。字符串
nuypyhwy3#
这是非常令人惊讶的行为,但被广泛宣布为不是一个错误。PHP(在撰写本文时)没有块级变量。如果您期望
$item
在退出循环时超出范围,您会发现它没有。下面是一个简单的例子:
字符串
哪些输出:
型
正如其他人已经说过的,您正在使用第二个循环覆盖
$arr[2]
中的引用变量,但这只是因为$item
从未超出范围。yizd12fk4#
PHP的正确行为在我看来应该是一个NOTICE错误。如果在foreach循环中创建的引用变量在循环外使用,则应引起注意。很容易被这种行为所迷惑,当它发生时很难发现。没有开发人员会去阅读foreach文档页面,它没有帮助。
你应该在循环后
unset()
引用以避免这种问题。对引用使用unset()只会删除引用,而不会损害原始数据。68bkxrlz5#
这是因为您使用了by ref指令(&)。最后一个值将被第二个循环替换,它会破坏你的数组。最简单的解决方案是为第二个循环使用不同的名称:
字符串