PHP BLT #4 で PHP の興味深い挙動を知った
そこで @uzulla さんが雑談的に発表された内容に面白いものがありまして。
たしかこんな感じのやつ。
$values = [ 'a' => null, 'b' => 'abc', ]; foreach ($values as $key => &$value) { $value[$key] = '123'; // 本当は $key[$value] = '123' の意図 }
ここで間違えて $key と $value を入れ替えて記述したのはいいけど、$value が null の時にはエラーにならなくて、abc の時に初めて
PHP Warning: Illegal string offset 'b' in /some/path/hoge.php on line X
なんてのが出るという話。
値が null の変数は未定義と等しく扱われるので、そこで変数の生成と代入が同時に行われる。null は未定義と等しいのは以下の例をみても分かる。
$a = null;
var_dump(isset($a)); // 結果は bool(false)
で、先の uzulla さんのコードを、エラーを出さないようにキーが 'b' の要素を抜いて実行すると、当然エラーにはならず $values は以下のようになる。
$values = [ 'a' => null, ]; foreach ($values as $key => &$value) { $value[$key] = '123'; } var_dump($values);
実行結果:
array(1) { ["a"]=> &array(1) { ["a"]=> string(3) "123" } }
あれ? なんで配列が入れ子になるんだろうと不思議に思ったので、色々試してみたところ挙動が理解できた。
この場合 foreach でループを回す際の $value に & がついて参照になっていることがキモで、ループ内で新たな配列が作られた後、それが $values キー 'a' の値として上書きされているということになる。
分かりやすく代替コードで示すとこう。
foreach ($values as $key => &$value) { $tmp[$key] = '123'; $value = $tmp; }
参照をやめれば、当然ながら要素の上書きは起こらない。
$values = [ 'a' => null, ]; foreach ($values as $key => $value) { $value[$key] = '123'; } var_dump($values);
実行結果:
array(1) { ["a"]=> NULL }