2012-04-18 86 views
0

可能重複:
Strange behavior Of foreach奇怪的PHP行爲 - 發生了什麼?

只是碰到這種錯誤的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

+0

重用引用時,這是一個衆所周知的副作用。我確信遍地都有重複的問題。 '第一次循環後取消設置($ item)'。 – deceze 2012-04-18 01:49:39

+0

嗯,我很高興人們寧願把它稱爲一個衆所周知的副作用,而不是一個bug :) – Ben 2012-04-18 01:56:42

+1

@FelixKling謝謝你的參考。投票結束我自己的問題(不要以爲我曾經這樣做過) – Ben 2012-04-18 01:56:56

回答

0

你需要使用的foreach與引用數組後取消設置的指針。

http://php.net/unset

+0

爲什麼downvotes? – dotancohen 2012-04-18 01:49:07

+0

這是對的。 [PHP手冊的foreach頁面說](http://us3.php.net/manual/en/control-structures.foreach.php)「引用$ value和最後一個數組元素在foreach循環之後仍然保留。建議通過unset()來銷燬它。「 – dotancohen 2012-04-18 01:52:22

+0

我以爲你寫了'reset',而不是'unset'。 upvoted,現在我要去睡覺.. – 2012-04-18 01:54:47

1

這就是會被周圍幾乎永遠奇PHP的行爲,當你混合使用的變量作爲參考再沒有提及像你這樣它發生。

我使用命名約定來處理它,如下所示:當我使用foreach&$item時,我將它命名爲&$refItem。這使我不能混合類型。

+0

好的建議 – Ben 2012-04-18 01:57:02

2

首先,它不像Rasmus所說的那樣是一個bug。請參閱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 
} 

?> 
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分配一些東西時,它會做些什麼,將東西放在那個東西里面。

在第一環路 $項的結束是指針到$項[1] 第一個第二環路 的它將第一元件推到該位置,其中$項目點(意味着$項[1],因此爲什麼$項目[1]是由$替換項目的[0]。

如果你想避免這個,只是取消設置下一次使用前在$項目變量。

0

這是一個正常的,而不是一個奇怪的行爲。只是閱讀有關參考here

當您在變量前添加&時,會將引用存儲到變量中。所以,當你重新使用它時,它也會改變被引用變量的內容。

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); 
} 

爲了解決這個問題,添加未設置($項目)的第一環:

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