6

是否可以在 PHP 中每当调用类中的函数时触发事件,而不将其添加到类中的每个函数中?

例子:

<?php
    class A {
        function xxx() {
            //this function will be called everytime I call another function in this class  
        }

        public static function b() {
            return 'Hello Stackoverflow!';
        }

        public static function c() {
            //I also want this function to trigger the event!
        }
    }

    echo A::b();
?>
4

4 回答 4

15

AFAIK 对此没有母语结构。如果您出于调试目的需要它,我建议您深入了解 xdebug 扩展,尤其是函数跟踪(太棒了!:)

另一个想法是__call()在您的类中实现并包装所有公共方法。但这需要更改代码并有其他副作用:

(简化示例)

class Test {

    protected $listeners;

    public function __construct() {
        $this->listeners = array();
    }

    private function a() {
        echo 'something';
    }

    private function b() {
        echo 'something else';
    }

    public function __call($fname, $args) {
        call_user_func_array(array($this, $fname), $args);
        foreach($this->listeners as $listener) {
            $listener->notify('fname was called');
        }
    }

    public function addListener(Listener $listener) {
        $this->listeners[]= $listener;
    }
}

.

 class Listener {

     public function notify($message) {
         echo $message;
     }

 }

例子:

 $t = new Test();
 $l = new Listener();
 $t->addListener($l);

 $t->a();
于 2013-06-04T15:57:14.843 回答
3

这是面向方面编程 (AOP) 的经典任务。PHP 没有对 AOP 的原生支持,但是,有一些框架使 PHP 中的 AOP 成为可能。其中之一是GO!AOP PHP 框架。您还可以使用runkit实现 AOP 。

于 2013-06-04T16:03:18.630 回答
0

您需要 PHP SplObserver:来自 PHP Doc

于 2014-10-12T21:48:40.973 回答
0

这是依赖注入和延迟初始化的经典任务!依赖项是 MySQL 连接。因为它首先需要在执行第一个查询时可用,所以它不需要在“启动”时初始化,而只是在那时。这称为延迟初始化,其实现极其简单:

class DbStuff {
  private $__conn = NULL;

  protected function _getConn() {
    if ( is_null( $this->__conn ) {
      $this->__conn = ... ;  // init (MySQL) DB connection here
      // throw on errors!
    }
    return $this->__conn;
  }

  public function someQuery($arg1, $arg2) {
    $conn = $this->_getConn();
    // MySQL query here:
    ...
  }
}

所需的所有“重构”都是调用$this->_getConn()每个查询方法。

面向方面的编程不是解决这个问题的工具,因为数据库连接是查询的固有依赖关系,而不是它的一个方面。自动记录所有执行的查询是一个方面。

围绕 PHP 构建的触发器__call()也不是一个好的选择。除了取消现代 IDE 的检查(可以快速查看模块是否良好)之外,它会不必要地使测试复杂化:$this->_getWhatever()可以在测试外观对象中轻松覆盖受保护的对象(从要测试的类派生)以返回模拟对象管他呢。使用__call(),为了相同的目的需要更多的代码,这会导致代码中出现错误的风险,而这些代码仅用于测试(并且应该绝对没有错误)

于 2016-09-13T13:49:07.720 回答