【问题标题】:PHP: Callback on Entry/Exit of Class Methods?PHP:类方法的进入/退出回调?
【发布时间】:2008-11-14 00:29:18
【问题描述】:

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

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

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

        // Do some stuff...

        Logger::logExit();
    }
}

【问题讨论】:

    标签: php logging methods callback stack-trace


    【解决方案1】:

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

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

    .

    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);
    

    【讨论】:

      【解决方案2】:

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

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

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

      __call 的问题

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

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

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

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

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

      【讨论】:

      • 绝对同意,但是如果必须这样做(无论出于何种原因),我更喜欢不将记录器与其尝试记录的类绑定的方法。
      【解决方案3】:

      你可以使用魔法函数__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"
      

      【讨论】:

      • 给用户的函数加前缀真的很糟糕。
      • 它不会更改任何其他人的代码 - 您必须更改自己的代码。或者,只需将方法更改为私有或受保护。
      猜你喜欢
      • 1970-01-01
      • 2020-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-03
      • 2011-01-18
      • 2018-04-03
      • 2011-02-04
      相关资源
      最近更新 更多