Help us understand the problem. What is going on with this article?

今更PHP5とPHP7の違いを肌で感じてみる(配列編)

More than 1 year has passed since last update.

仕事で久しぶりにPHPに触れることになりそうなのでウォーミングアップのつもりで今更ながらPHP7にチャレンジ。(PHP8の足音が。。。)

昔PHP5やってたのでその辺との違いを比較してみる。
一言で比較と言っても色々な観点があるし環境とか組み方も見なきゃだけど、まあウォーミングアップなので細かいことは置いておく。

とは言え比較の観点は決めておこう。
PHP5からPHP7では色々と変わったけど、データ構造・配列構造が改善されたのとBucket構造体が変わったとの話があったので、
今回はその観点で検証しようと思う。

PHP5までは要素が数値でも連想配列として扱っていたものが、PHP7では数値の場合はいわゆる一般的な配列として扱われるようになった。
また、bucket構造体がメモリの連続確保になったことによって、連続的なアクセスに強くなった。
という事は、数値を要素とした配列のforやforeachが早くなったはず。

よし、検証開始。

比較観点

  • 最大メモリ使用量
  • 処理速度

比較環境

  • 端末:Macbook Air
  • CPU:Core i5 1.3GHz
  • メモリ:4GB 1600MHz DDR3
  • OS:Sierra 10.12.6

検証対象

  • PHP5 … PHP 5.6.32 (cli) (built: Oct 27 2017 11:56:18)
  • PHP7 … PHP 7.0.26 (cli) (built: Dec 2 2017 13:12:39) ( NTS )

検証

検証方法

土台としてこんな感じの検証コードを用意。
配列をループで回して検証するシンプルなものだけど、シンプルじゃないと純粋な計測にならないのでこの程度で。
良いブログがあったので参考にさせていただきました。
(参考: https://qiita.com/h13/items/a75fba76f435212a2eb3)

base.php
<?php
        $baseMem = memory_get_usage();
        $startTime = microtime(true);

        for ($i = 0; $i < 100; $i++) {
                $data = range(1, 100000);
                // {***ここに後述の検証パターン処理を差し込む***}

                $data = null;
        }

        $maxMem = (memory_get_peak_usage() - $baseMem) / (1024 * 1024); // 最大メモリ使用量
        $processTime = microtime(true) - $startTime; // 処理時間

検証パターン1. foreach

foreach.php
                $output = [];
                foreach ($data as $value) {
                        $output[] = $value;
                }

検証パターン2. foreachでメモリ節約

foreach-eco.php
                foreach ($data as $key => $value) {
                        $output[] = $value;
                        unset($data[$key]);
                }

検証パターン3. foreachで参照渡し

foreach-ref.php
                foreach ($data as &$value) {
                        $output[] = $value;
                }

検証パターン4. foreachで参照渡しでメモリ節約

foreach-ref-eco.php
                foreach ($data as &$value) {
                        $output[] = $value;
                        unset($value);
                }

検証パターン5. while

while.php
                $output = [];
                while (list(, $value) = each($data)) {
                        $output[] = $value;
                }

検証パターン6. whileのメモリ節約

while-eco.php
                while (list($key, $value) = each($data)) {
                        $output[] = $value;
                        unset($data[$key]);
                }

検証結果

検証番号 [PHP5] 最大メモリ(MB) [PHP5] 時間(秒) [PHP7] 最大メモリ(MB) [PHP7] 時間(秒) [PHP7効果] 最大メモリ(MB) [PHP7効果] 時間(秒)
1 27.96 4.68 8.008 0.80 約 1/3 約 1/6
2 28.20 6.08 12.012 1.37 約 1/2 約 1/4
3 27.95 4.90 10.297 0.98 約 1/3 約 1/5
4 27.95 5.63 10.297 1.00 約 1/3 約 1/6
5 28.20 12.9 8.008 3.08 約 1/4 約 1/4
6 28.06 7.22 8.008 3.56 約 1/4 約 1/2

まあ、言わずもがなですが圧倒的な差が出ましたね。

全体的にPHP7が圧倒的に速くなった理由は、そもそもL1キャッシュを利用できるとかコンパイル時にASTを噛ませるようになったとかも影響してるのだろうけど、その辺の実証はまたいずれ。(その頃はPHP7とPHP8の検証の方がいいかもだけど)

おまけ

今回とは少しズレるけどPHP7ではイテレートの変数に対して内部ポインタを使わなくなってるので、PHP5でcurrent()とかreset()とか使ってる状態でPHP7にすると結果が変わってしまう。
要注意のメモ。

おまけのおまけ

Merry X'mas!!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした