ツイート
シェア
LINEで送る
B! はてぶでブックマーク
Pocketでブックマーク
RSSフィード

PHP extract, EXTR_PREFIX_IF_EXISTS で不可思議な結果になる。

php
イラストダウンロードサイト【イラストAC】
の画像をもとに加工しています。

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リファレンス

引用の色が付いてる部分をプレフィックスが付いてると勘違いするだけでドキュメントにも書いてない意図しない結果になります。

これ、バグになりやすいので注意しましょう。ドキュメントにも書いてないことが起きてるのでパニックに陥る可能性大です。

シンボルテーブルとは、宣言済みの変数のリストのこと。

宣言済みとはisset() でtrueを返すもの。

PHP公式ドキュメント

Function - extract

前の投稿
PHP, urlencode() は rawurlencode() に変えるべき?
PHP extract, いろいろな変数展開の方法。変数名かぶり回避のオプションもある。
次の投稿
コメントを残す

*