概念理解:在某一个事件(trigger)发生的时候,触发预先设定(on)的代码,这是代码解耦的一种方式。

事件按照级别分为三类

1. 实例级别

绑定事件、触发事件的类继承的是Component,只在当前示例中运行,不与类的其他实例发生关系,也不与其他类、其他实例发生关系。

代码示例:<?phpnamespace common\components;use yii\base\Component;class EventTest extends Component{    const EVENT_SAY_HELLO = 'say_hello';        public function sayHello($event)    {        echo $event->data;        $event->handled = true;    }        public function sayWorld($event)    {        echo $event->data;    }}1.绑定事件:$event = new EventTest();$event->on(EventTest::EVENT_SAY_HELLO, [$event, 'sayHello'], 'Hello!');$event->on(EventTest::EVENT_SAY_HELLO, [$event, 'sayWorld'], 'World!');2.解除事件:$event->off(EventTest::EVENT_SAY_HELLO, [$event, 'sayHello']);4.触发事件:$event->trigger( EventTest::EVENT_SAY_HELLO);

2. 类级别

绑定事件、触发事件的类继承的是Event,类级别事件会被类自身、类的实例、后代类、后代类实例的同一事件所触发,影响范围更大

代码示例:<?phpnamespace common\components;use yii\base\Event;class EventTest extends Event{    const EVENT_SAY_HELLO = 'say_hello';        public function sayHello($event)    {        echo $event->data;    }        public function sayWorld($event)    {        echo $event->data;    }}1.绑定事件:$event = new EventTest();$event->on('\common\components\EventTest', EventTest::EVENT_SAY_HELLO, [$event, 'sayHello'], 'Hello!');$event->on('\common\components\EventTest', EventTest::EVENT_SAY_HELLO, [$event, 'sayWorld'], 'World!');2.解除事件:$event->off('\common\components\EventTest', EventTest::EVENT_SAY_HELLO, [$event, 'sayWorld']);        触发事件:$event->trigger('\common\components\EventTest', EventTest::EVENT_SAY_HELLO);类级别参数比实例级别多一个参数:类名
注意:解除事件如果不传 handle,则会解除该事件下的所有 handle。在其中一个 handle 里面加上 $event->handled = true 也会阻止后续 handle 的触发,如上代码。

3. 全局级别

利用Application实例在整个应用的生命周期中全局可访问的特性,来实现这个全局事件的。在任意需要的时候,都可以触发全局事件,也可以在任意必要的时候绑定,或解除一个事件。

代码示例:绑定事件:$event = new EventTest();Yii::$app->on('global_event', [$event, 'globalEvent'], 'global event');触发事件:Yii::$app->trigger('global_event');全局级别实际上也是一个特殊的实例。[注意所谓全局其实作用范围也只是在当前请求的生命周期有效,而非当前会话(简单的说,打开浏览器,访问服务器,直到浏览器关闭,称为一次会话)]

原理

实例级别通过维护Component类的属性 $_events 数组,触发事件时通过[事件名称]取到[当前实例]的handle数据,再通过函数call_user_func触发handle

类级别通过维护Event类的属性 $_events 数组,触发事件时通过[类名和事件名称]取到[当前类以及父类]的handle数据,再通过函数call_user_func触发handle

Component 的 $_event 数据结构示例如下

Array(    [say_hello] => Array        (            [0] => Array                (                    [0] => Array                        (                            [0] => common\components\EventTest Object                                (                                    [_events:yii\base\Component:private] => Array *RECURSION*                                    [_eventWildcards:yii\base\Component:private] => Array                                        (                                        )                                    [_behaviors:yii\base\Component:private] => Array                                        (                                        )                                )                            [1] => say_hello                        )                    [1] => Hello!                )        ))

小结

以上总结参考了深入理解Yii2.0,其实以前就看过,但是也只是局限于看过,没有自己跑demo调试、查看源代码,然后就误以为自己明白了,其实过俩天什么都不记得了。所以现在通过写博客来加深自己的理解,这篇博客其实主要讲的还是事件的使用,具体原理一带而过,如果有小伙伴一知半解,可能查看一下源代码[yii\base\Component yii\base\Event]你就明白了。由于水平有限,欢迎小伙伴交流和指正。