マジックメソッドの動作速度

検証:マジックメソッドの動作速度

マジックメソッド(__get, __set)を使用したプロパティアクセスと、

マジックメソッドを使用しないプロパティアクセスの動作速度を検証しました

結果としては、マジックメソッドは遅いです

絶対値で見れば僅かな差ですが、相対的に見ると約15倍通常のプロパティアクセスの方が高速です

プロパティが1つの場合

テストコード

<?php

// CLIなら
、ブラウザなら<br>
define('NL', php_sapi_name() === 'cli' ? "\n" : "<br>");

// 計測結果の少数第何位まで表示するか
define('ROUND_DIGIT', 10);

function benchmark($name, $test_fn, $step = 10) {
    $times    = array();
    $memories = array();

    for($ii = 0; $ii < $step; $ii++) {
        $start = time() + microtime();

        $test_fn();
        $memories[] = memory_get_usage(true);

        $end = time() + microtime();

        $sub = $end - $start;
        $current = $ii + 1;
        echo sprintf("%d/%d  => %.".ROUND_DIGIT."f%s", $current, $step, $sub, NL);

        $times[] = $sub;
    }

    $total_time_ms = array_sum($times) * 1000;
    $total_memory  = array_sum($memories);

    echo "=============================================".NL;
    echo sprintf("Result for '%s'%s", $name, NL);
    echo sprintf("Time:total:   %.".ROUND_DIGIT."f ms%s", $total_time_ms, NL);
    echo sprintf("Time:average: %.".ROUND_DIGIT."f ms%s", $total_time_ms / $step, NL);
    echo sprintf("Memory:average:   %d B (%.4f MB)%s", $total_memory / $step, ($total_memory / $step) / 1024, NL);
    echo sprintf("Memory:max:   %d B (%.4f MB)%s", memory_get_peak_usage(true), memory_get_peak_usage(true) / 1024, NL);
    echo "=============================================".NL.NL;
}

define('TEST', 1000);

set_time_limit(600);

// マジックメソッドを使用しないクラス
class Model {
    public $id = 1;
}
// マジックメソッドを使用するクラス
class MagicModel {
    public $attributes = array(
        'id' => 1,
    );

    public function __set($name, $value) {
        $this->attributes[$name] = $value;
    }

    public function __get($name) {
        return $this->attributes[$name];
    }
}

benchmark('マジックメソッドを使用しないプロパティアクセス', function() {
    $model = new Model();
    for($ii = 0; $ii < 10000; $ii++) {
        $tmp = $model->id;  // 取得
        $model->id = $ii;   // 設定
    }
});

benchmark('マジックメソッドを使用したプロパティアクセス', function() {
    $model = new MagicModel();
    for($ii = 0; $ii < 10000; $ii++) {
        $tmp = $model->id;  // 取得
        $model->id = $ii;   // 設定
    }
});

ベンチマーク結果

1/10  => 0.0022928715
2/10  => 0.0022192001
3/10  => 0.0021739006
4/10  => 0.0021870136
5/10  => 0.0022110939
6/10  => 0.0024940968
7/10  => 0.0043790340
8/10  => 0.0033369064
9/10  => 0.0035238266
10/10  => 0.0023758411
=============================================
Result for 'プロパティ1つのクラスでマジックメソッドを使用しないプロパティアクセス'
Time:total: 27.1937847137 ms
Time:average:   2.7193784714 ms
Memory:average: 262144 B (256.0000 MB)
Memory:max: 262144 B (256.0000 MB)
=============================================

1/10  => 0.0422289371
2/10  => 0.0485138893
3/10  => 0.0372209549
4/10  => 0.0458679199
5/10  => 0.0456209183
6/10  => 0.0451428890
7/10  => 0.0421690941
8/10  => 0.0383639336
9/10  => 0.0446751118
10/10  => 0.0502278805
=============================================
Result for 'プロパティ1つのクラスでマジックメソッドを使用したプロパティアクセス'
Time:total: 440.0315284729 ms
Time:average:   44.0031528473 ms
Memory:average: 262144 B (256.0000 MB)
Memory:max: 262144 B (256.0000 MB)
=============================================

プロパティを増やした場合

マジックメソッドはプロパティを走査するため、

プロパティを走査するのであれば、プロパティが増えれば取得にかかる時間も増えるという仮説のためにクラスとベンチマークスクリプトを少し書き換えます

ネクストエンジンAPIの商品マスタから取得できる項目を、

すべてクラスのプロパティとして定義し、その動作速度を検証します

これは、商品マスタの情報をDBに蓄積して利用するモデルがある想定です

テストコード

class Model {
    public $goods_id = 1; // 商品コード
    public $goods_representation_id = 1; // 代表商品コード
    public $goods_name = 1; // 商品名

    // 長いので省略
}
class MagicModel {
    public $attributes = array(
        'goods_id' => 1, // 商品コード
        'goods_representation_id' => 1, // 代表商品コード
        'goods_name' => 1, // 商品名

        // 長いので省略
    );
}

結果を先に説明すると、相対的に遅くなっています

ベンチマーク結果

1/10  => 0.0039870739
2/10  => 0.0042259693
3/10  => 0.0039098263
4/10  => 0.0054919720
5/10  => 0.0052731037
6/10  => 0.0038580894
7/10  => 0.0054771900
8/10  => 0.0068209171
9/10  => 0.0062510967
10/10  => 0.0057909489
=============================================
Result for 'プロパティ110個のクラスでマジックメソッドを使用しないプロパティアクセス'
Time:total: 51.0861873627 ms
Time:average:   5.1086187363 ms
Memory:average: 524288 B (512.0000 MB)
Memory:max: 524288 B (512.0000 MB)
=============================================

1/10  => 0.0822989941
2/10  => 0.0844771862
3/10  => 0.0775389671
4/10  => 0.0746560097
5/10  => 0.0761110783
6/10  => 0.0804190636
7/10  => 0.0751941204
8/10  => 0.0845780373
9/10  => 0.0734241009
10/10  => 0.0821299553
=============================================
Result for 'プロパティ110個のクラスでマジックメソッドを使用したプロパティアクセス'
Time:total: 790.8275127411 ms
Time:average:   79.0827512741 ms
Memory:average: 524288 B (512.0000 MB)
Memory:max: 524288 B (512.0000 MB)
=============================================

  • 2015/02/17: 検証:マジックメソッドの動作速度ページ作成