PHP:类方法的进入/退出回调?

时间:2008-11-14 00:29:18

标签: php logging methods callback stack-trace

有没有办法在不在每个方法中进行显式调用的情况下设置回调(或自动记录)方法参数,条目和出口?我基本上想要将这些信息记录到我的记录器类(这是静态的),而不必为每个方法手动执行。

现在我必须在每个方法中调用Logger :: logEntry()和Logger :: logExit()来完成此任务。我很乐意不必这样做:

class TestClass {
    public function tester($arg) {
        Logger::logEntry();
        Logger::info('Parameter $arg => ' . $arg);

        // Do some stuff...

        Logger::logExit();
    }
}

3 个答案:

答案 0 :(得分:11)

使用包装类。这种方法有以下好处:

  • 无需更改基础类结构/方法签名
  • 更改日志记录?只是更新这个课程
  • 更新对象调用vs将代码插入到您要记录的每个类

class LogWatch {
    function __construct($class)    {
        $this->obj  =   $class;
    }

    function __call($method, $args) {
        if (in_array($method, get_class_methods($this->obj) ) ) {
            Logger::logEntry();
            Logger::info('Parameter '.implode(', ', $args) );

            call_user_func_array(array($this->obj, $method), $args);

            Logger::logExit();

        } else {
            throw new BadMethodCallException();
        }
    }
}

$test = new LogWatch(new TestClass() );
$test->tester();

// you can use instances of `LogWatch()` just like your watched class
// including passing appropriate params:
$test->tester($param1, $param2);

答案 1 :(得分:5)

如果您想为了调试而进行功能记录,您可能需要查看Xdebug扩展。在运行时没有很好的方法来拦截函数调用,任何自动拦截都会增加很大的运行时开销。

使用XDebug你可以根据需要打开它,以及获得许多其他东西

(因此,XDebug与PHPUnit一起用于单元测试和覆盖率分析。)

__call

的问题

__调用可能看起来是一个有趣的问题解决方案,但这有 3 问题,即

  • 重大执行开销。你在做__call - > call_user_func_array,它实际上不会为每次执行添加一个,而是两个函数调用。

  • Backtraces变得无法解读:你试图调用的实际函数在__call和call_user_func_array的海洋中迷失,使得回溯变得非常困难,特别是如果你的回溯带有他们的arguent列表。

  • 愚蠢的隐藏函数:你回到PHP4风格“隐藏”函数的前提是用_来阻止用户直接调用它或看到它,因为如果函数名恰好被命名为什么不,__ call不会触发,所以你已经有了一整套真正可怕的函数名称,开发人员很想在各个地方直接调用。 (如果你想在以后删除__call,你必须重命名所有这些函数,以免破坏代码!)

因此,如果您正在使用PHP代码来实现这将导致严重可怕的代码,您的代码库的任何未来用户将 NOT 想要使用。获得可以在需要时透明添加的东西(如Xdebug)要好得多,并且可以大大节省污染代码。

答案 2 :(得分:-1)

你可以使用魔术函数__call。当没有函数匹配该名称时,它会被调用。将您的方法重命名为前缀(例如:下划线),并可选择将它们设置为private / protected。

class TestClass {
    public function __call($function, $args) {
        Logger::logEntry();
        Logger::info('Parameters: ' . implode(", ", $args);

        $localFunc = "_" . $function;
        $return = $this->$localFunc($args);

        Logger::logExit();

        return $return;
    }

    private function _tester() {
        // do stuff...
        return "tester called";
    }
}

 $t = new TestClass();
 echo $t->tester();
 // "tester called"