1

重複の可能性:
foreach の奇妙な動作

最近、PHP アプリでこのバグに遭遇しました。何が起こっているのかわからない。

foreach基本的には2つ(&あり、なし)を組み合わせて使用​​した場合に現れます。

問題を再現するテスト コードを次に示します。

$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
}

2 番目のforeachループでは、予想どおりブロックが 2 回実行されますが$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の動作であり、参照として変数の使用を混合した場合に発生しますが、実際のように参照ではありません。

私はそれを次のように命名規則で扱います:私がで使用foreachしているとき&$item、私はそれをのように命名し&$refItemます。これにより、タイプを混在させることができなくなります。

于 2012-04-18T01:50:20.653 に答える
0

参照される配列でforeachを使用した後は、ポインターの設定を解除する必要があります。

http://php.net/unset

于 2012-04-18T01:48:17.820 に答える
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の問題をより理解しているように見えるものかもしれません

$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 参照に戻ります。これで、2 番目の foreach で $item に何かを割り当てると、その中に何かが置かれます。

最初のループの最後で $item は$items[1] へのポインタです[1] は $items[0] に置き換えられます。

これを防ぎたい場合は、次回使用する前に $item 変数の設定を解除してください。

于 2012-04-18T02:09:21.700 に答える