【PHP】ループ構文の速度比較とパフォーマンス低下の原因(while、for、foreach)【PHP高速化】

Webサイト制作
2019.09.30

プログラムというものはは基本的に分岐とループの組み合わせで作られています。
その中で今回のPHP高速化ではループの部分に焦点を当てていこうと思います。

PHPでのループ関数

PHPには3つのループ関数があります。
while、for、foreachになります。
それぞれの特徴は以下の通りになります

  • while:条件に一致する間繰り返す
  • for:カウント変数の定義とインクリメントを行い条件に一致する間繰り返す
  • foreach:配列の中の値を先頭からループ取り出す(配列の値の数だけ繰り返す)
  • PHPは配列の処理が得意な為、基本的にforeachを使うことが多いです。
    ですが、配列の添字を工夫する事でどのループでも同じ動作をさせる事が可能です。

    配列を扱い場合の速度

    PHPのループ関数を同じ配列を操作した際の速度を比較してみました。
    なるべく可動性の高いコードの記述方法うを選択しています。

    <?php
    // whileの動作 
    $start_time_while = microtime(true);
    $array_count = count($test_array);
    $while_count = 0;
    while($while_count < $array_count) {
        $test = $test_array[$while_count];
        $while_count++;
    }
    $end_time_while = microtime(true);
    // forの動作
    $start_time_for = microtime(true);
    for($for_count=0; $for_count<count($array_count); $for_count++) {
        $test = $test_array[$for_count];
    }
    $end_time_for = microtime(true);
    // foreachの動作
    $start_time_foreach = microtime(true);
    foreach($test_array as $test_data) {
        $test = $test_data;
    }
    $end_time_foreach = microtime(true);
    
    echo 'while処理時間:'.($end_time_while - $start_time_while)."秒\n";
    echo 'for処理時間:'.($end_time_for - $start_time_for)."秒\n";
    echo 'foreach処理時間:'.($end_time_foreach - $start_time_foreach)."秒\n";
    

    出力結果は以下のようになりました。
    数回試してみましたが大きく結果が変わるものはありませんでした。

    while処理時間  :0.0050520896911621秒
    for処理時間    :5.9604644775391E-6秒
    foreach処理時間:0.0044721832275391秒
    

    結果としてはforのみが著しく遅くforeachとwhileは大きくは変わらないがforeachの方が若干早いということが分かりました。
    では、何故forのみが処理時間かかかってしまっているのでしょうか?

    forの処理時間がかかった原因

    forの処理時間が他の2つと比べ大幅に処理時間がかかってしまっている原因を検証したいと思います。
    forはwhileと比較した場合、処理自体に大きな差異はありません。
    挙げるとすれば、forの場合、カウント変数の宣言、条件の比較、カウント変数のインクリメントの3点をforの中で行っています。
    whileは条件の比較の際に事前に取得した配列のカウントを使用していますが、forの処理では条件比較の際にカウント関数を使用しています。
    こちらをwhileの処理と合わせ事前にカウント数を取得するように変更しました。

    <?php
    // forの動作
    $start_time_for = microtime(true);
    $array_count = count($test_array);
    for($for_count=0; $for_count<$array_count; $for_count++) {
        $test = $test_array[$for_count];
    }
    $end_time_for = microtime(true);
    

    出力結果は以下になりました。

    for処理時間:0.0054850578308105秒
    

    forだけが著しく遅かった問題が解決したと思われます。
    何度か試しましたが、速度はforeach、while、forの順に早いという結果は変わりませんでした。

    この結果から、whileやforの条件部分はループの度動作する為、処理はなるべくループの外で記述するべきであるという事が分かりました。
    また、常にforeachが一番速く処理をしていた点から、配列を使用する際のループはforeachが適切であり
    場合によっては事前に処理する値を配列にする事でwhileやforではなくforeachを使用したほうが処理が速く終わる場合があるという事も分かりました。

    まとめ

    何気なく使用しているループ関数ですが
    処理速度という観点から見た際に、いつもと違う側面が見えた気がしました。
    それぞれの関数で処理速度が多少ではありますが異なり、更に条件式の書き方に気をつけないと
    著しくパフォーマンスを低下させる
    場合があるので注意しなくてはならないと思います。

    SEOやWEB制作に関する情報を検索する

    コラム

    最新コラム

    人気コラム

    過去の記事

    ご質問やご相談などお気軽にお問い合わせください。