🐘

PHPのforeachで参照渡しを使ったときの落とし穴

2013/08/23に公開

PHP の foreach は参照渡しも使える

まず前提ですが、以下のように $value に & を付けることで、foreach で参照渡しが使えます。

foreach ($array as &$value) {
  // do something.
}

foreach ($array as $key => &$value) {
  // do something.
}

ループ内で配列の中身を上書きしたいときにコードがスッキリして便利なんですが、むやみに使っていると思わぬバグを引き起こすことがあるので注意が必要です。

悪い例

$array = array(1, 2, 3);
foreach ($array as &$value) {
  // do nothing.
}
$value = 10;
var_dump($array);

出力結果

array(3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  &int(10) ← こいつがおかしい
}

良い例

$array = array(1, 2, 3);
foreach ($array as &$value) {
  // do nothing.
}
unset($value);  // これが重要.
$value = 10;
var_dump($array);

出力結果

array(3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
}

解説

お察しのとおり、foreach を抜けた時点で $value は $array の最終要素のポインタを保持している ので(PHPにはブロックスコープがないので)、別の用途に $value を使おうとして、何も考えずに何かを代入すると $array の最終要素が上書きされてしまうわけですね。

良い例で示したように、$value を unset しておけば参照は解除されるので問題は起こりません。
foreach で参照渡しを使う際は覚えておきましょう。

GitHubで編集を提案

Discussion