多くの人々は、そのような構造を何らかの形で書くのが好きです、誰もが遭遇しました:
foreach ($items as &$item) { $item += 2; }
しかし、多くの人がここに潜んでいる危険を疑っていません。
例を考えてみましょう。
Vasya Pupkinは配列を取得し、それに沿って歩いて、すべての要素を2つ増やしました。
$items = array( 'a' => 10, 'b' => 20, 'c' => 30, ); foreach ($items as &$item) { $item += 2; } print_r($items);
私はダンプを見て、問題が解決したことを見て、満足したままにしておきました:
Array ( [a] => 12 [b] => 22 [c] => 32 )
しばらくして、Petrovichはコードのこのセクションを別の検索で補完することを決定し、以下を追加しました。
$newitems = array( 'a' => 10, 'b' => 20, 'c' => 30, ); foreach ($newitems as $key=>$item) { $newitems[$key] += 5; } print_r($newitems);
彼は自分のタスクも解決されたように見え、達成感を持ってファイルを閉じました。
Array ( [a] => 15 [b] => 25 [c] => 35 )
しばらくして、説明できないバグが出始めました。 なんで?
コードの最後でvar_dump($アイテム)を実行しましょう:
array(3) { ["a"]=> int(12) ["b"]=> int(22) ["c"]=> &int(30) }
30! Vasya Pupkinはチェックしたことを誓います。 なぜ32で、ペトロビッチコード30の後ですか?
その理由はアンパサンドにあります。 彼は、他の誰かがマークされたデータを参照していると報告します。 退出する際、Vasyaは反復に使用した一時変数($アイテム)を消去しませんでした。 この変数は、「参照による割り当て」とも呼ばれるソース(「&」)を変更する権限で使用されました。 彼は、変数がループ内でのみ使用されると確信していました。 Petrovichは、列挙中に同じ名前の変数を使用して値を変更し、この変数が格納されている場所が変わるたびに変更しました。 そして、それはパプキン山塊の最後の要素と同じ場所に保存されました。
もちろん、記事が誇張されている場合。 実際、そのような関係は、特にプロジェクトが安価で、経験豊富で異なるWeb開発者が十分に参加していない場合、非常に複雑になる可能性があります。
どのようにこれを処理できますか?
結論として、リンクに関連するバグはforeachだけではない可能性があると言います。 そして、それらのすべてがかつて議論されました。 しかし、私の経験から判断すると、このケースは実際に広まっているため、特別な注意に値します。