[PHP] range関数によるforeach文でfor文に挑んでみる

PerlやRubyには(“01″..”10″);や[1..10]といったお馴染みのrange指定による配列の書き方があるのにPHPにはなくて残念、と思っていたPHPerです。

これまで知らなかっただけで、PHPにもrange(1, 10)という近い役割の関数があることを最近知りました。

range指定が使えれば、一定数で回したい時などに直感的に書けて便利そうです(Rubyでは10.timesとかもありますが)。
 

PHPでお馴染みのforeachを使うと、

for ($i = 1; $i < = 10; $i++) {
    echo $i;
}

foreach (range(1, 10) as $i) {
    echo $i;
}

みたいな置き換えが考えられます(何も考えずに書けそう)。
 

ただし、楽に書けるのはいいのですが、一般にforeachはforよりも処理速度が遅いという問題がネックになりそうです。

ということで、どれくらい速度差があるのか、検証して見ることにしました。

 

forとforeachの処理速度を計測してみる

環境

  • Windows上のVM
  • CentOS6.2
  • PHP 5.4.2 (cli)

for文のテストコード

$max = $argv[1];
$startTime = microtime(true);

for ($i = 1; $i < = $max; $i++) {
    echo "{$i}\n";
}

$endTime = microtime(true);
$spendTime = round($endTime - $startTime, 3);
echo "\nspend:{$spendTime}\n"

foreach文のテストコード

$max = $argv[1];
$startTime = microtime(true);

foreach (range(1, $max) as $i) {
    echo "{$i}\n";
}

$endTime = microtime(true);
$spendTime = round($endTime - $startTime, 3);
echo "\nspend:{$spendTime}\n"

計測結果

それぞれ5回ずつ試行した結果の平均値をまとめてみます。

対象 1万件 10万件 100万件
A. for文 0.035秒 0.277秒 2.864秒
B. foreach文 0.040秒 0.290秒 3.074秒
差(B – A) 0.040秒 0.290秒 3.074秒

for文の方が遅いのは確かですが、件数が1万件、10万件の場合の差は10ミリ秒以下と意外と少なかったです。
100万件だと200ミリ秒くらいの差が出てきますね。

もう少しforeachがんばれないかなーということで、少しコードをいじってみます。
 

forとforeach(改良版)で処理速度を計測してみる

foreachに渡すrange関数の結果の値を先に変数に入れてから、やってみます。

foreach文のテストコード(改良版)

$max = $argv[1];
$startTime = microtime(true);

$range = range(1, $max);
foreach ($range as $i) {
    echo "{$i}\n";
}

$endTime = microtime(true);
$spendTime = round($endTime - $startTime, 3);
echo "\nspend:{$spendTime}\n"

計測結果

先ほどと同じように、それぞれ5回ずつ試行した結果の平均値をまとめてみます。

対象 1万件 10万件 100万件
A. for文 0.035秒 0.277秒 2.864秒
B. foreach文(改良版) 0.033秒 0.268秒 2.914秒
差(B – A) -0.002秒 -0.009秒 0.050秒

なんと、件数が1万件、10万件の場合はforeachの方がほんのちょっと速い結果になりました。
100万件の場合だと若干for文のほう50ミリ秒速いものの、1/4まで差が縮まったことが見てとれます。

まとめ

思ってたよりもforeach文ががんばってくれた結果になりました。
レスポンスにシビアな処理や、かなり大量のデータを扱う処理でない限り、range関数を使ったforeach文でもまったく問題ないのではないでしょうか。

普段使いのバッチ処理や、テストコードなんかでは活躍する場面がありそうです。

さらにforeach文の改良版(range関数の結果の値を先に変数に入れておく)であれば、変数定義で多少手軽さは失われますが、誤差のレベルまで速度は縮まります。

今回の結論(ざっくり)

  • 意外とforeachがんばってくれる
  • レスポンスにシビアな処理でない限り、十分に代用できそう
  • PHP5.4系の恩恵ももしかしたらあるのかも

 
viva PHP