foreach的奇怪行为

时间:2011-02-11 12:58:04

标签: php arrays foreach

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

有人可以向我解释一下吗?

2 个答案:

答案 0 :(得分:87)

这是一个记录良好的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'.

答案 1 :(得分:3)

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

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

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