forの公式通りの最適化 at 低回数

**特に目新しい要素はありません。**

# Q

低回数の`for`ループでも最適化したほうがいい？

# A

何回でも最適化したほうがいい。
大体1.5~2倍早くなる…かも。

# <i class="fa fa-cubes"></i> 概要

[forの最適化は公式にものっています]が、巷の速度検証はパッと見

1. `for`,`foreach`,`while`の比較
2. 10000回以上のループ時の最適化結果

などがよく出てきます。
でも、実際使うループって、ちっさい奴の方が多くて、多くて数十回。
条件によるが、1,2回が多いよーってループもあります。

そんなループが毎回`count`しているとして、それを最適化するべきか。

1. 改善したとして、2,3回のループでは誤差の範囲なのでは？
2. 変数を増やすことで、低回数では逆転現象が起きるのでは？

という、9割方ありえないと言える疑問が出たので解消しておきます。

# <i class="fa fa-code"></i> コード

```php

<?php

function benchmark($name, $repeat, $action)
{
    $sumNormal = 0.0;
    $sumBetter = 0.0;
    for ($i = 0; $i <= $repeat; ++$i) {
        list($normal, $better) = $action($name);
        $sumNormal += $normal;
        $sumBetter += $better;
    }
    echo "[$name]\n";
    printf("Repeat: %d\n", $repeat);
    printf("SumNormal: %.6f\n", $sumNormal);
    printf("SumBetter: %.6f\n", $sumBetter);
    printf("AverageNormal: %.12f\n", $sumNormal / $repeat);
    printf("AverageBetter: %.12f\n", $sumBetter / $repeat);
}

function loop($repeat)
{
    $array = range(1, $repeat);
    $start = microtime(true);
    for ($i = 0, $tmp = array(); $i < count($array); ++$i) {
        $tmp[] = $array[$i];
    }
    $end = microtime(true);
    $normal = $end - $start;

    $start = microtime(true);
    for ($i = 0, $tmp = array(), $arrayCount = count($array); $i < $arrayCount; ++$i) {
        $tmp[] = $array[$i];
    }
    $end = microtime(true);
    $better = $end - $start;
    return array($normal, $better);
}

for ($i = 1; $i <= 20; ++$i) {
    benchmark($i, 1000, function ($i) {
        return loop($i);
    });
}

```

[別記事で頂いたコメント]のコードが使いやすそうだったので少しお借りしましたが、その他が微妙…
一応、1~20回のループの実行時間を、最適化前後で取ることを目的としたコードです。
`for`内は何でも良かった。

## 関係無いこと

コールバックとクロージャーを使いこなせていませんでした。
`callback $action`に関数の結果やクロージャーを渡しまくって怒られたので、
結局タイプヒンティングを外すことに…
クロージャーへのループ回数も`$name`使っちゃったりで要調べ直しですわ…

# 結果

1000回の平均値です。

| 回数 | 最適化前       | 最適化後       | 差             |
|------|----------------|----------------|----------------|
| 1    | 0.000001803875 | 0.000001413107 | 0.000000390768 |
| 2    | 0.000002399206 | 0.000001653671 | 0.000000745535 |
| 3    | 0.000002686262 | 0.000002104044 | 0.000000582218 |
| 4    | 0.000003310680 | 0.000002167940 | 0.000001142740 |
| 5    | 0.000003662825 | 0.000002414465 | 0.000001248360 |
| 6    | 0.000003905773 | 0.000002634525 | 0.000001271248 |
| 7    | 0.000004558802 | 0.000002737999 | 0.000001820803 |
| 8    | 0.000005032063 | 0.000002932310 | 0.000002099753 |
| 9    | 0.000005578995 | 0.000003361940 | 0.000002217055 |
| 10   | 0.000006055355 | 0.000003500700 | 0.000002554655 |
| 11   | 0.000006258249 | 0.000003766298 | 0.000002491951 |
| 12   | 0.000006690502 | 0.000004018307 | 0.000002672195 |
| 13   | 0.000007185936 | 0.000004022360 | 0.000003163576 |
| 14   | 0.000007489681 | 0.000004143476 | 0.000003346205 |
| 15   | 0.000008211851 | 0.000004441023 | 0.000003770828 |
| 16   | 0.000008442402 | 0.000004733324 | 0.000003709078 |
| 17   | 0.000008889675 | 0.000004783630 | 0.000004106045 |
| 18   | 0.000009706736 | 0.000005150318 | 0.000004556418 |
| 19   | 0.000009850264 | 0.000005435944 | 0.000004414320 |
| 20   | 0.000010215759 | 0.000005474091 | 0.000004741668 |

実際には、最適化前コードは大抵後置インクリメントになってることが多いので、もう少し差がでるはずです。

最適化の効果はすぐに結果に現れました。
が、元々の処理時間が短いので、新規で書くのはともかく、現行のコードを直す価値はこの速度差にあるのでしょうか…？
その辺の基準や、0.00001秒の差が及ぼすシステム全体への影響がわかりません。
少なくともユーザーの応答待ちの体感は変わらないと思うのですが。

# <i class="fa fa-file-text-o"></i> 参考文献

[今すぐできるPHP高速化　5つのポイント]
少し離れているが、今回と同じような3回ループの比較ができた。
同時に`foreach`が速いという結論ですが…
[パフォーマンスのためにPHPのfor文でcountを使うべきではない]
1000回以上のパフォーマンス比較。
ベンチマークかっこいい。

他にもたくさんあると思いますが、キーワードの違いとかですぐに見失いますね…
大体高速化は2~3倍というのが多いようです。

[パフォーマンスのためにPHPのfor文でcountを使うべきではない]:http://kaworu.jpn.org/kaworu/2008-01-28-2.php
[forの最適化は公式にものっています]:http://php.net/manual/ja/control-structures.for.php
[別記事で頂いたコメント]:http://qiita.com/khsk/items/cf084162cda02d466e55#comment-2d5d9d1a07445a6efe3f
[今すぐできるPHP高速化　5つのポイント]:http://wp.tech-style.info/archives/123