PHPで複数の値で条件分岐したいときにin_array()を使うのはどうなの?
例えばこんなとき
<?php
// a~zのアルファベットの値が入ったら真としたい
$str = 'a';
if (in_array($str, array(
'a',
'b',
'c',
// ~~
'z')
)
) {
// 小文字のアルファベットですね!
} else {
// 小文字のアルファベットではないですね!
}
?>
(例みたいな時はpreg_match()なんかでもいいと思うけど)
||(OR)演算子やswitchで比較する方法もあるけど
速度はどうなの?気になって試してみました。
速度も大事だけど、可読性といった点も気になります。
in_array()は嫌われ者?
その配列の中に同等の値があるか検索する関数です。
PHPを勉強し始めた頃に
in_array()は遅い、罠があるから注意(厳密な比較をしない、第3引数の真偽)なんて聞いてから
嫌われてる関数なのかな?と思っていた関数のひとつ。
というわけでなんとなく敬遠してたin_array()。
条件分岐で複数の値で真としたい処理のときに
||演算子で比較する場合、switchを使う場合、in_array()を使う場合と比較して
in_array()は本当に遅いのか試してみた結果です。
使用したPHPのバージョンは7.3系です。
in_array()に加えて||演算子、switch文で書いた時、それぞれ100万回比較した速度を測りました。
<?php
// a~zのアルファベットの値が入ったら真としたい
$str = 'a';
$ave = 0;
// 結果を平均化するために10回
for ($j = 0; $j < 10; $j++) {
$start = microtime(true);
// 比較を100万回行う
for ($i = 0; $i < 1000000; $i++) {
if (in_array($str, array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'))) {
// 小文字のアルファベットですね!
}
}
// 処理にかかった時間
$end = microtime(true);
$ave += $end - $start;
}
echo $ave;
?>
<?php
// a~zのアルファベットの値が入ったら真としたい
$str = 'a';
$ave = 0;
// 結果を平均化するために10回
for ($j = 0; $j < 10; $j++) {
$start = microtime(true);
// 比較を100万回行う
for ($i = 0; $i < 1000000; $i++) {
if ($str == 'a' || $str == 'b' || $str == 'c' || $str == 'd'
|| $str == 'e' || $str == 'f' || $str == 'g' || $str == 'h'
|| $str == 'i' || $str == 'j' || $str == 'k' || $str == 'l'
|| $str == 'm' || $str == 'n' || $str == 'o' || $str == 'p'
|| $str == 'q' || $str == 'r' || $str == 's' || $str == 't'
|| $str == 'u' || $str == 'v' || $str == 'w' || $str == 'x'
|| $str == 'y' || $str == 'z') {
// 小文字のアルファベットですね!
}
}
// 処理にかかった時間
$end = microtime(true);
$ave += $end - $start;
}
echo $ave;
?>
<?php
// a~zのアルファベットの値が入ったら真としたい
$str = 'a';
$ave = 0;
// 結果を平均化するために10回
for ($j = 0; $j < 10; $j++) {
$start = microtime(true);
// 比較を100万回行う
for ($i = 0; $i < 1000000; $i++) {
switch ($str) {
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
// 小文字のアルファベットですね!
break;
}
}
// 処理にかかった時間
$end = microtime(true);
$ave += $end - $start;
}
echo $ave;
?>
結果(値が'a'のとき)
in_array() (in_array.php)
0.22234416007996(秒)
||演算子 (or.php)
1.583863735199(秒)
switch文 (switch.php)
0.2550265789032(秒)
||演算子で繋いだ場合は他の2つに比べてかなり遅いです。
条件式の最初の方に来れば速いのかと思いましたが、そうではない様子。
このサンプルの時に'z'が来ると、さらに速度差が出ます。
結果(値が'z'のとき)
in_array() (in_array.php)
0.23062896728516(秒)
||演算子 (or.php)
5.7600326538086(秒)
switch文 (switch.php)
0.26001954078674(秒)
in_arrayとswitchは誤差の範囲ですね。
注意しないといけないのは==や===演算子で比較するときは緩い比較なのか厳密な比較なのか視覚的に分かりやすいけど
switchやin_arrayは普通に使うと緩い比較であるということ(書き方や引数次第で厳密に出来るけど、その辺りはリファレンスや他の方の記事をご参考に)
なので厳密な比較をする方法も試してみました。
<?php
// a~zのアルファベットの値が入ったら真としたい
$str = 'z';
$ave = 0;
// 結果を平均化するために10回
for ($j = 0; $j < 10; $j++) {
$start = microtime(true);
// 比較を100万回行う
for ($i = 0; $i < 1000000; $i++) {
if (in_array($str, array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'), true)) { // 厳密な比較
// 小文字のアルファベットですね!
}
}
// 処理にかかった時間
$end = microtime(true);
$ave += $end - $start;
}
echo $ave;
?>
<?php
// a~zのアルファベットの値が入ったら真としたい
$str = 'z';
$ave = 0;
// 結果を平均化するために10回
for ($j = 0; $j < 10; $j++) {
$start = microtime(true);
// 比較を100万回行う
for ($i = 0; $i < 1000000; $i++) {
if ($str === 'a' || $str === 'b' || $str === 'c' || $str === 'd'
|| $str === 'e' || $str === 'f' || $str === 'g' || $str === 'h'
|| $str === 'i' || $str === 'j' || $str === 'k' || $str === 'l'
|| $str === 'm' || $str === 'n' || $str === 'o' || $str === 'p'
|| $str === 'q' || $str === 'r' || $str === 's' || $str === 't'
|| $str === 'u' || $str === 'v' || $str === 'w' || $str === 'x'
|| $str === 'y' || $str === 'z') {
// 小文字のアルファベットですね!
}
}
// 処理にかかった時間
$end = microtime(true);
$ave += $end - $start;
}
echo $ave;
?>
<?php
// a~zのアルファベットの値が入ったら真としたい
$str = 'z';
$ave = 0;
// 結果を平均化するために10回
for ($j = 0; $j < 10; $j++) {
$start = microtime(true);
// 比較を100万回行う
for ($i = 0; $i < 1000000; $i++) {
switch ($str) {
case $str === 'a':
case $str === 'b':
case $str === 'c':
case $str === 'd':
case $str === 'e':
case $str === 'f':
case $str === 'g':
case $str === 'h':
case $str === 'i':
case $str === 'j':
case $str === 'k':
case $str === 'l':
case $str === 'm':
case $str === 'n':
case $str === 'o':
case $str === 'p':
case $str === 'q':
case $str === 'r':
case $str === 's':
case $str === 't':
case $str === 'u':
case $str === 'v':
case $str === 'w':
case $str === 'x':
case $str === 'y':
case $str === 'z':
// 小文字のアルファベットですね!
break;
}
}
// 処理にかかった時間
$end = microtime(true);
$ave += $end - $start;
}
echo $ave;
?>
結果(値が'z'のとき、厳密な比較)
in_array() (in_array_strict.php)
0.24085545539856(秒)
||演算子 (or_strict.php)
7.8184959888458(秒)
switch文 (switch_strict.php)
8.6827254295349(秒)
switchがだいぶ遅くなりましたね。===による比較の処理も上乗せ?されるのでしょうか?
この場合ではin_array()が圧勝です。
用途や条件にもよるだろうけど、in_array()の「食わず嫌い」はちょっと考え直してもいいのかもという結果でした。