奇怪的PHP行为 - 发生了什么?

时间:2012-04-18 01:44:05

标签: php reference foreach

  

可能重复:
  Strange behavior Of foreach

最近在PHP应用中遇到了这个bug。不知道发生了什么。

基本上,当使用两个foreach(一个带&一个没有)的组合时会出现。

这是一个重现问题的测试代码:

$items = array(

    array('id'=>1, 'name'=>'foo', 'value'=>150),

    array('id'=>2, 'name'=>'bar', 'value'=>190)
);


foreach($items as &$item)
{

    $item['percentage'] = $item['value'] * 0.75;

}

var_dump($items);   // All Good

foreach($items as $item)
{

    var_dump($item);    // Shows 1st item twice
}

第二个foreach循环按预期运行块两次,但$item仍然停留在第一个项目上。

我知道在第一个循环中使用引用&可能会导致 ,但我不明白为什么它应该像这样......

有什么想法吗?那是一个错误吗?

在5.3.8,5.3.10&amp ;;上获得相同的结果5.4

5 个答案:

答案 0 :(得分:2)

首先,这不是Rasmus所说的错误。见https://bugs.php.net/bug.php?id=29992

在这个中,正确实现了使用&。

的循环变量修改数组
<?php
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
    $value = $value * 2;
}
// $arr is now array(2, 4, 6, 8)
unset($value); // break the reference with the last element

var_dump($arr);   // All Good

foreach($arr as $value) {
   var_dump($value);    // All good
}

?>

答案 1 :(得分:1)

这是奇怪的PHP行为,它几乎永远存在,当你混合使用变量作为参考而不是像你那样引用时就会发生。

我使用以下命名约定处理它:当我使用foreach &$item时,我将其命名为&$refItem。这使我无法混合类型。

答案 2 :(得分:0)

使用带有引用数组的foreach后,需要取消设置指针。

http://php.net/unset

答案 3 :(得分:0)

这可能是看起来更加了解foreach的问题

$last_value_of_first_foreach = 1;
$item = 2;
$c = 3;
$item = &$last_value_of_first_foreach ; // Think that this statement is first foreach loop
// Here $item is pointer to $last_value_of_first_foreach 
// To Better understanding, let change the name ($reference_to_last_value = $item;)

现在,新循环是

$item = $c;
// Here, what it do is update value where the $item pointer refer to 
// (mean $last_value_of_first_foreach )
// so, at here $last_value_of_first_foreach has value of $c

现在,回到你的情况,从第一个foreach,$ item引用到数组的最后一个元素。现在,当你在第二个foreach中为$ item分配一些东西时,它会做什么,就会把东西放在那个东西里面。

在第一个循环结束时 $ item是指针到$ items [1] 第二个循环的第一个 它会将第一个元素推送到$ item指向的位置(表示$ items [1],这样为什么$ items [1]被$ items [0]替换。

如果你想阻止这个,只需在下次使用之前取消设置 $ item变量。

答案 4 :(得分:0)

这是正常的,而不是奇怪的行为。请阅读有关参考here的信息。

当你添加&amp;在变量前面,存储对变量的引用。因此,当您重新使用它时,它也会更改引用变量的内容。

foreach($items as &$item) // You have $item here, prefixed with &.
{
    $item['percentage'] = $item['value'] * 0.75;
}

var_dump($items);

foreach($items as $item) // And your re-use it here.
{
    var_dump($item);
}

要解决此问题,请在第一个循环中添加unset($ item):

foreach($items as &$item)
{
    $item['percentage'] = $item['value'] * 0.75;
    unset($item); // add this, because you use &$item previously.
}