2012-04-18 2 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

Это хорошо известный побочный эффект при повторном использовании ссылки. Я уверен, что во всем мире есть повторяющиеся вопросы. 'unset ($ item)' после первого цикла. – deceze

+0

Ну, я рад, что люди скорее называют это известным побочным эффектом, а не ошибкой :) – Ben

+1

@FelixKling Спасибо за реф. Голосование, чтобы закрыть мой собственный вопрос (не думаю, что я когда-либо делал это раньше) – Ben

ответ

0

Вам нужно сбросить указатель после использования Еогеасп с ссылочного массива.

http://php.net/unset

+0

Почему downvotes? – dotancohen

+0

Правильно. В [странице руководства PHP на странице указано] (http://us3.php.net/manual/en/control-structures.foreach.php) «Ссылка на значение $ и последний элемент массива остаются даже после цикла foreach. рекомендуется уничтожить его unset(). ". – dotancohen

+0

Я думал, что вы написали 'reset', а не' unset'. Приобретенный, теперь я ложась спать .. –

1

Это странное поведение PHP, что было вокруг довольно много навсегда, и это происходит, когда вы смешиваете использование переменной в качестве ссылки, то не ссылаться, как вы делали.

Я занимаюсь этим соглашением об именах следующим образом: Когда я использую foreach с &$item, я называю его &$refItem. Это мешает мне смешивать типы.

+0

Хорошее предложение – Ben

2

Во-первых, это не ошибка, как сказал Расмус. См. 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

Это может быть что-то, что выглядит более понять проблему Еогеасп

$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 

Теперь вернемся к вашему делу, с первого Еогеасп , ссылка $ item на последний элемент массива. теперь, когда вы назначаете что-то в $ item во втором foreach, что он делает, помещается что-то внутри этого.

В конце первого цикла $ изделия указатель до $ пунктов [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); 
} 

Чтобы решить эту проблему, добавьте незадана ($ пункт) в 1-м цикле:

foreach($items as &$item) 
{ 
    $item['percentage'] = $item['value'] * 0.75; 
    unset($item); // add this, because you use &$item previously. 
} 
Смежные вопросы