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 ($items as &$item) $item += 2; unset($item);
- 誰かがすでに使用している変数には注意してください。
- アクションを個別の関数、メソッド、または名前空間にカプセル化します。
- print_rの代わりにvar_dumpを使用し、アンパサンドに注意してください。 ブラウザではなくファイルにダンプするには、print_r($ var、true)の代わりに次のような構造を使用します。
function dump() { ob_start(); foreach(func_get_args() as $var) var_dump($var); return ob_get_clean(); }
結論として、リンクに関連するバグはforeachだけではない可能性があると言います。 そして、それらのすべてがかつて議論されました。 しかし、私の経験から判断すると、このケースは実際に広まっているため、特別な注意に値します。