PHPのループで参照渡しを使ったコードが思い通りの挙動にならず、いろいろ調べてたら面白い例を見つけたので紹介。
こんなコードがあったとする。
$a = array('a', 'b', 'c', 'd');
foreach ($a as &$v) {}
print_r($a);
foreach ($a as $v) {}
print_r($a);
2回のprint_r($a);
の結果は同じになりそうなものだけど実際は以下のようになる。
Array
(
[0] => a
[1] => b
[2] => c
[3] => d
)
Array
(
[0] => a
[1] => b
[2] => c
[3] => c
)
なぜかというと、まず1個目のループは参照渡しなので、
$vがaが入ってる1個目のコンテナ(※)を指す
$vがbが入ってる2個目コンテナを指す
$vがcが入ってる3個目コンテナを指す
$vがdが入ってる4個目コンテナを指す
という流れで$v
のポインターが4個目のコンテナに移動する。
※コンテナ = 値の格納場所。「zval」とも呼ばれる
2個目のループの間$v
は4個目のコンテナに対するポインターとして機能しているので、
$v=aで4個目のコンテナの中身がaになる
$v=bで4個目のコンテナの中身がbになる
$v=cで4個目のコンテナの中身がcになる
という現象が起き、上記の時点で配列の中身がabcc
になってしまう。
対策としては、一個目の配列の後にunset($v)
で$v
→4個目のコンテナの参照を切ると解消される。
$a = array('a', 'b', 'c', 'd');
foreach ($a as &$v) {}
print_r($a);
unset($v);
foreach ($a as $v) {}
print_r($a);
Array
(
[0] => a
[1] => b
[2] => c
[3] => d
)
Array
(
[0] => a
[1] => b
[2] => c
[3] => d
)
参考