こんにちは、アシアルの井川です。
Webサイトやバッチ処理のパフォーマンスを考える際、気を付けることは多々あります。全体の構造、アルゴリズムの効率化、…。その中の一つに、個々の関数の仕組みと実行速度の問題があります。関数の仕様は言語レベルで決定されており、それらを把握していないと、時としてパフォーマンスの大きな低下を招きます。今回焦点を当てるのは、配列要素を確認する際によく使われる関数です。
さて、皆さんは配列内に要素が存在するか否かを判定する場合、どうされていますか?この確認には、isset、array_key_exists、in_arrayなどいくつかの方法があります。isset、 array_key_existsは配列のキー値が存在するか確認し、in_arrayは要素の値を確認します。例えば、
<?php
$list = array('a' => 1, 'b' => 1, 'c' => 1, 'd' => 1, 'e' => 1);
if (isset($list['a'])) {
// 何らかの処理
}
if (array_key_exists('a', $list)) {
// 何らかの処理
}
$list = array('a', 'b', 'c', 'd', 'e');
if (in_array('a', $list)) {
// 何らかの処理
}
などと記述します。この中でよく見かけるのは、in_arrayを使った方法です。使いやすい上に、直感的にも理解しやすい便利な関数です。
ただし、大量のデータを扱うさいにはお勧めできません。なぜならば、in_arrayの実行時間はO(n)だからです(in_arrayは要素を一つずつ確認していきます)。一方で、issetとarray_key_existsはO(1)で結果を返します(PHPの連想配列はハッシュであり、添字配列ではインデクスを使用してます)。
もちろん、ごく少数のデータを扱うのであれば、各関数の一回あたりの実行時間は微々たるもの(マイクロ秒以下)であり、それほど気にすることはありません。
しかしながら、要素数が多い場合や、これらの関数を多用する際には注意が必要でしょう。例えば、以下の図は、要素数の増加と、全要素を各関数で確認した場合の一回あたりの実行時間を測定した結果です。横軸は配列の要素数であり、縦軸は平均実行時間です。
要素数が100程度なら、array_key_existsとin_arrayの実行時間はさほど変わりませんが、要素数が増加するとその差がはっきりと現れます。配列の要素チェックをする場合、可能なら、連想配列を用いてissetやarray_key_existsを使いましょう。また、計測すると、issetの方が約1.8倍ほど速い結果となりました。
ただし、issetとarray_key_existsでは挙動が異るので注意が必要です。公式マニュアルによると、
isset — 変数がセットされていること、そしてNULLでないことを検査する
array_key_exists — 指定したキーまたは添字が配列にあるかどうかを調べる
となっています。すなわち、
<?php
$list = array('a' => null);
$bool = isset($list['a']); // false
$bool = array_key_exists('a', $list); // true
となるので注意が必要です。配列要素にNULL値が入っていない(もしくは無視できる)状況なら、issetがお勧めです。些細なことに感じるかもしれませんが、時として意外と重要だったりします。