PHPでAOP的にメソッドの実行時間を計測


PHPでAOP的にメソッドの実行時間を計測

概要

  • 特定のインスタンスの呼び出されるメソッド全ての計測をしたい
  • そのクラスのソースコードは(できる限り)かえたくない

こういったものを実現します。

サンプル

code

<html>
<body>
<?php

class PHoge {
  public function getPHoge() {
    return "getPHoge called!!";
  }
}

class Hoge extends PHoge {

    public $hoge;
    public static $hogeStatic = "hoge static";

    public function __construct() {
        $this->hoge = "hoge prop";
        $this->_hoge = "_hoge prop";
    }

    public function getHoge() {
        return $this->_getHoge();
    }

    private function _getHoge() {
        return "_getHoge is called";
    }

    public static function getHogeStatic() {
        return "getHogeStatic is called";
    }
}

class MethodIntercepter {

    private $_instance;
    private static $_className;

    public function __construct($instance) {
        $this->_instance = $instance;
        $ref = new ReflectionClass($instance);
        self::$_className = $ref->getName();
    }

    public function __call($method, $arguments) {

        $timeStart = microtime(true);
        $ret = call_user_func_array(array($this->_instance, $method), $arguments);
        $timePassed = microtime(true) - $timeStart;
        $timePassed *= 1000;        
        $calledMethod = self::$_className . "->{$method}";
        $calledMethodArgs = json_encode($arguments, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        echo "{$calledMethod}({$calledMethodArgs}):{$timePassed}ms<br />";

        return $ret;
    }

    public static function __callStatic($method, $arguments) {

        $timeStart = microtime(true);
        $ret = call_user_func_array(array(self::$_className, $method), $arguments);
        $timePassed = microtime(true) - $timeStart;
        $timePassed *= 1000;
        $calledMethod = self::$_className . "::{$method}";
        $calledMethodArgs = json_encode($arguments, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        echo "{$calledMethod}({$calledMethodArgs}):{$timePassed}ms<br />";

        return $ret;
    }

    public function __get($key) {

        return $this->_instance->$key;
    }

    public function __set($key, $value) {

        $this->_instance->$key = $value;
    }
}

$hoge = new Hoge();
$hoge = new MethodIntercepter($hoge); // MethodIntercepter でくるむ
echo $hoge->getPHoge() . '<br />';
echo $hoge->getHoge() . '<br />';
echo $hoge->hoge . '<br />';
$hoge->hoge = "hoge prop is changed";
echo $hoge->hoge . '<br />';
echo $hoge::getHogeStatic() . '<br />';
echo Hoge::$hogeStatic . '<br />'; // $hoge::$hogeStatic はできない @see http://stackoverflow.com/questions/1279382/magic-get-getter-for-static-properties-in-php
?>
</body>
</html>

実行結果

使い方

  1. MethodIntercepter というクラスを定義します
  2. 計測したいインスタンスを MethodIntercepterでラップします

これだけで、計測したいインスタンスのメソッドの呼び出し全てに対して実行時間を計測できるようになります。
MVCなどで、Controllerに設定されるModelインスタンスに対して適用するなどすると便利です。