foreachの落とし穴($アイテムとして&$アイテム)

多くの人々は、そのような構造を何らかの形で書くのが好きです、誰もが遭遇しました:
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だけではない可能性があると言います。 そして、それらのすべてがかつて議論されました。 しかし、私の経験から判断すると、このケースは実際に広まっているため、特別な注意に値します。

Source: https://habr.com/ru/post/J136835/


All Articles