【问题标题】:Logging all operations: the good design pattern?记录所有操作:好的设计模式?
【发布时间】:2012-12-05 11:19:36
【问题描述】:

我有一堂课:

class Phone
{
    public function addnewnumber ($name, $number)
    {
    }
}

现在让我们假设我想要记录所有操作。我不想在addnewnumber() 中添加Logger::add(); 之类的内容-也许无法修改该类。那怎么解决呢?

【问题讨论】:

    标签: php


    【解决方案1】:

    在某些情况下,您可以使用代理类来包装您的对象并允许您使用__call 转发函数调用。它看起来像这样:

    class Proxy
    {
        private $_target;
        public function __construct($target)
        {
            $this->_target = $target;
        }
    
        public function __call($name, $params)
        {
            $callable = array($this->_target, $name);
            if (!is_callable($callable)) {
                trigger_error('Call to undefined method '.
                               get_class($this->_target).'::'.$name, E_USER_ERROR);
            }
    
            return $this->dispatch($callable, $params);
        }
    
        protected function dispatch($callable, $params)
        {
            return call_user_func_array($callable, $params);
        }
    }
    

    然后您可以从此类派生并覆盖 dispatch 以执行自定义处理:

    class LoggingProxy extends Proxy
    {
        protected function dispatch($callable, $params)
        {
            echo "Before calling ".get_class($callable[0]).'::'.$callable[1]."\n";
            $return = parent::dispatch($callable, $params);
            echo "After calling ".get_class($callable[0]).'::'.$callable[1]."\n";
            return $return;
        }
    }
    

    并像这样使用它:

    $proxy = new LoggingProxy(new Phone);
    $proxy->addnewnumber(1, 2);
    

    See it in action.

    但是,这种方法确实有一些缺点:

    • 它不适用于需要特定类型对象的代码(您传递的是 Proxy 而不是 Phone
    • 它不允许您访问包装类的非公共成员

    【讨论】:

      【解决方案2】:

      您不能在每个类的每个方法上自动调用某些日志记录功能。如果你想在手机的 addnewnumber 方法中添加日志记录,而不改变类本身,你可以在你自己的类中扩展它。

      class Phone
      {
          public function addnewnumber($name, $number)
          {
          }
          public function somethingelse()
          {
          }
      }
      
      class MyPhone extends Phone
      {
          public function addnewnumber($name, $number)
          {
              Logger::Add();
              parent::addnewnumber($name, $number);
          }
      }
      

      现在您的 MyPhone 类具有所有电话方法,但是当调用 addnewnumber 方法时,它会记录号码,然后调用实际方法。

      【讨论】:

      • 那么方法的参数必须跟在扩展类后面,这不是一种“过度劳累”吗?
      • 发送动态参数见stackoverflow.com/questions/1603469/…。但是,是的,它总是有些工作。但这就是它在 PHP 中的方式。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-09-11
      • 1970-01-01
      • 1970-01-01
      • 2012-06-18
      • 2015-02-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多