【php】array_key_exists は isset より1000倍以上遅いことがある
※これはphp5.6以前の問題で、php7系では発生しません。
通常は、array_key_exists(‘hoge’, $arr) と isset($arr[‘hoge’]) はほとんど処理速度に違いがない。
ただ、状況によっては、array_key_exists を使った処理が isset より極端に遅いことがある。
検証
// 速い(issetは言語構造) $a = range(0, 10000); for ($i = 0; $i < 10000; ++$i) { isset($a[$i]); } // → 0.0029 秒
// 速い(参照を作ってもあまり変わらない) $a = range(0, 10000); $b = &$a; for ($i = 0; $i < 10000; ++$i) { isset($b[$i]); } // → 0.0029 秒
// 速い(関数呼び出しのオーバーヘッドかな?程度の誤差) $a = range(0, 10000); for ($i = 0; $i < 10000; ++$i) { array_key_exists($i, $a); } // → 0.0033 秒
// 遅い(参照を作ると遅い) $a = range(0, 10000); $b = &$a; for ($i = 0; $i < 10000; ++$i) { array_key_exists($i, $b); } // → 9.5 秒
// 遅い(なんと参照を作られても遅い) $a = range(0, 10000); $b = &$a; for ($i = 0; $i < 10000; ++$i) { array_key_exists($i, $a); } // → 9.5 秒
なぜ?
phpのソースを確認すると、array_key_exists は、引数を受け取るときに zend_parse_parameters() を使っています。
「zend_get_parameters() は、参照をチェックします。 参照が見つかった場合には、独立した zval コンテナを新しく作成し、参照先のデータをそこにコピーし、 その新しく作成した (他とは分離している) コンテナへのポインタを返します。」なのだそうで、参照を作るとコピーを作るようになってしまうので遅くなるということのようです。
補足
array_key_exists と isset は動作が若干違います。
$arr[‘hoge’] = NULL のとき、array_key_exists(‘hoge’, $arr) は true、isset($arr[‘hoge’]) は false を返します。
高速化のためなどで置き換えるときは注意しましょう。
コメント