foreach 的奇怪行为

Posted

技术标签:

【中文标题】foreach 的奇怪行为【英文标题】:Strange behavior Of foreach 【发布时间】:2011-06-25 13:12:27 【问题描述】:
<?php
  $a = array('a', 'b', 'c', 'd');

  foreach ($a as &$v)  
  foreach ($a as $v)  

  print_r($a);
?>

我认为这是一个正常的程序,但这是我得到的输出:

Array
(
    [0] => a
    [1] => b
    [2] => c
    [3] => c
)

谁能给我解释一下?

【问题讨论】:

"i think, its normal prog but web i saw op.........then ....ahh wat is it" 是什么意思? @Bart Kiers:他似乎在发呆。 Unintentional destruction of php array element? 的可能重复项 这是对这种行为的最好解释:schlueters.de/blog/archives/141-References-and-foreach.html Strange behaviour after loop by reference - Is this a PHP bug?的可能重复 【参考方案1】:

这是有据可查的 PHP 行为 请参阅 php.net 的 foreach 页面上的warning

警告

$value 的引用和最后一个数组元素即使在 foreach 循环之后仍然存在。建议通过 unset() 销毁。

$a = array('a', 'b', 'c', 'd');

foreach ($a as &$v)  
unset($v);
foreach ($a as $v)  

print_r($a);

编辑

尝试了解此处实际发生的情况的分步指南

$a = array('a', 'b', 'c', 'd');
foreach ($a as &$v)     // 1st iteration $v is a reference to $a[0] ('a')
foreach ($a as &$v)     // 2nd iteration $v is a reference to $a[1] ('b')
foreach ($a as &$v)     // 3rd iteration $v is a reference to $a[2] ('c')
foreach ($a as &$v)     // 4th iteration $v is a reference to $a[3] ('d')

                          // At the end of the foreach loop,
                          //    $v is still a reference to $a[3] ('d')

foreach ($a as $v)      // 1st iteration $v (still a reference to $a[3]) 
                          //    is set to a value of $a[0] ('a').
                          //    Because it is a reference to $a[3], 
                          //    it sets $a[3] to 'a'.
foreach ($a as $v)      // 2nd iteration $v (still a reference to $a[3]) 
                          //    is set to a value of $a[1] ('b').
                          //    Because it is a reference to $a[3], 
                          //    it sets $a[3] to 'b'.
foreach ($a as $v)      // 3rd iteration $v (still a reference to $a[3]) 
                          //    is set to a value of $a[2] ('c').
                          //    Because it is a reference to $a[3], 
                          //    it sets $a[3] to 'c'.
foreach ($a as $v)      // 4th iteration $v (still a reference to $a[3]) 
                          //    is set to a value of $a[3] ('c' since 
                          //       the last iteration).
                          //    Because it is a reference to $a[3], 
                          //    it sets $a[3] to 'c'.

【讨论】:

@Manish Trivedi:请参阅 警告 部分了解为什么会发生这种情况。你的程序没有问题。 很好的解释!谢谢:D 我必须记住一个作为参考/欺骗,所有其他关于使用 foreach 参考的答案都没有像你在这里所做的那样解释它! 在你的unset($v); 中,为什么$v 可以在foreachs 范围之外访问? :o @nawfal - 不明白这个问题.... PHP 局部变量范围在函数内,而不仅仅是在循环内 @MarkBaker 谢谢。你回答了我的问题。刚刚开始掌握 PHP 特性 :)【参考方案2】:

第一个 正如我们所期望的那样,foreach 循环不会对数组进行任何更改。 但是,它确实会导致为$v 分配对$a 的每个元素的引用, 因此,当第一个循环结束时,$v 实际上是对$a[2] 的引用。

第二个循环一开始,$v 就被赋予了每个循环的值 元素。但是,$v 已经是对 $a[2]; 的引用,因此,任何值 分配给它的会自动复制到数组的最后一个元素中!

因此,在第一次迭代期间,$a[2] 将变为 0,然后变为 1,然后 再一次,被有效地复制到自己身上。为了解决这个问题,你 应始终取消设置您在按引用 foreach 中使用的变量 循环——或者,更好的是,完全避免使用前者。

【讨论】:

以上是关于foreach 的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 jQuery foreach 进入多维数组?奇怪的行为

PHP foreach 删除数组元素

PHP Foreach 通过引用传递:最后一个元素重复? (错误?)[重复]

在 foreach 循环中死亡时未按良好顺序执行的行

mysql 和 codeigniter 的奇怪插入行为

删除循环中的控件会导致奇怪的行为