1

有没有一种方法可以设置回调(或自动记录)方法参数、条目和退出,而无需在每个方法中进行显式调用?我基本上想将此信息记录到我的记录器类(它是静态的)中,而不必为每个方法手动执行。

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

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

        // Do some stuff...

        Logger::logExit();
    }
}
4

3 回答 3

11

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

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

.

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);
于 2008-11-14T01:18:54.580 回答
5

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

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

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

__call 的问题

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

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

  • 回溯变得难以辨认:您尝试调用的实际函数在 __call 和 call_user_func_array 的海洋中迷失了,这使得回溯变得异常困难,尤其是当您的回溯包含它们的争论列表时。

  • 愚蠢的隐藏函数:你将回到 PHP4 风格的函数“隐藏”,通过在函数前面加上 _ 来阻止用户直接调用或看到它,因为如果函数名称恰好被命名为他们不想要的名称,则 __call不会触发,所以你已经有了一个充满了非常可怕的函数名的整个类,开发人员会很想在各个地方直接调用它们。(如果你想稍后摆脱 __call,你将不得不重命名所有这些函数,以免破坏代码!)

因此,如果您使用 php 代码来实现这将导致极其可怕的代码,您的代码库的任何未来用户都不想使用。你最好得到一些可以在需要时透明地添加的东西(比如 Xdebug ),并大大减少对代码的污染。

于 2008-11-14T01:16:23.680 回答
-1

你可以使用魔法功能__call。当没有函数匹配该名称时,它会被调用。将您的方法重命名为以某些东西为前缀(例如:下划线),并可选择将它们设置为私有/受保护。

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"
于 2008-11-14T00:33:44.920 回答