PHPには、連想配列から変数展開する関数 extract() がありますが、EXTR_PREFIX_IF_EXISTS を使うとリファレンスにも書いてない不思議な結果になることがあります。
たった1つの勘違いでこの結果になるので注意が必要。
EXTR_PREFIX_IF_EXISTS をextract() のパラメータに指定すると、プレフィックスを付ける前の既存変数が存在する場合だけプレフィックス付き変数に展開します。
<?php
$val1 = 'test';
$arr = [
'val1' => 'sample1',
'val2' => 'sample2',
'val3' => 'sample3',
];
extract($arr, EXTR_PREFIX_IF_EXISTS, 'next');
if(isset($val1)) {
echo 'val1 => ' . $val1 . PHP_EOL;
}
if(isset($next_val1)) {
echo 'next val1 => ' . $next_val1 . PHP_EOL;
}
if(isset($next_val2)) {
echo 'next val2 => ' . $next_val2 . PHP_EOL;
}
if(isset($next_val3)) {
echo 'next val3 => ' . $next_val3 . PHP_EOL;
}
実行結果
val1 => test
next val1 => sample1
で、ここからが本題。
既存変数名をプレフィックス付加後の変数名($next_val1)にするとこんな結果が出ます。
<?php
$next_val1 = 'test';
$arr = [
'val1' => 'sample1',
'val2' => 'sample2',
'val3' => 'sample3',
];
extract($arr, EXTR_PREFIX_IF_EXISTS, 'next');
if(isset($val1)) {
echo 'val1 => ' . $val1 . PHP_EOL;
}
if(isset($next_val1)) {
echo 'next val1 => ' . $next_val1 . PHP_EOL;
}
if(isset($next_val2)) {
echo 'next val2 => ' . $next_val2 . PHP_EOL;
}
if(isset($next_val3)) {
echo 'next val3 => ' . $next_val3 . PHP_EOL;
}
実行結果
val1 => sample1
next val1 => test
なんと、プレフィックスを付けない変数($val1)が展開されます。この動きはPHPの公式ドキュメントにも書かれていません。
しかも、EXTR_PREFIX_IF_EXISTS の説明がややこしい。
同じ変数だが接頭辞をつけていないバージョンの変数が 現在のシンボルテーブルに存在する場合にのみ 変数を生成します。
PHPリファレンス
引用の色が付いてる部分をプレフィックスが付いてると勘違いするだけでドキュメントにも書いてない意図しない結果になります。
これ、バグになりやすいので注意しましょう。ドキュメントにも書いてないことが起きてるのでパニックに陥る可能性大です。
PHP公式ドキュメント