1

可能重复:
foreach 的奇怪行为

最近在一个 PHP 应用程序中遇到了这个错误。不知道发生了什么。

基本上,它在使用两个组合时出现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 和 5.4 上获得相同的结果

4

5 回答 5

3

首先,这不是 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
}

?>
于 2012-04-18T02:00:06.347 回答
2

这是一种奇怪的 PHP 行为,几乎一直存在,当您混合使用变量作为引用而不是像您所做的那样引用时,就会发生这种情况。

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

于 2012-04-18T01:50:20.653 回答
0

这是正常的,不是奇怪的行为。只需阅读此处的参考资料。

当您在变量前面添加 & 时,您将存储对变量的引用。所以,当你重新使用它时,它也会改变被引用变量的内容。

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.
}
于 2012-04-18T14:28:32.127 回答
0

在将 foreach 与引用数组一起使用后,您需要取消设置指针。

http://php.net/unset

于 2012-04-18T01:48:17.820 回答
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 变量。

于 2012-04-18T02:09:21.700 回答