浅析Yii2.0的事件Event

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

事件按照级别分为三类

1. 实例级别

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

代码示例:

<?php

namespace 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']);

3.触发事件:

$event->trigger( EventTest::EVENT_SAY_HELLO);

2. 类级别

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

代码示例:

<?php

namespace 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']);
        

3.触发事件:

$event->trigger('\common\components\EventTest', EventTest::EVENT_SAY_HELLO);

类级别参数比实例级别多一个参数:类名
注意:
解除事件若是不传 handle,则会解除该事件下的全部 handle。
在其中一个 handle 里面加上 $event->handled = true 也会阻止后续 handle 的触发,如上代码。

3. 全局级别

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

代码示例:

1.绑定事件:
$event = new EventTest();

Yii::$app->on('global_event', [$event, 'globalEvent'], 'global event');

2.触发事件:
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]你就明白了。因为水平有限,欢迎小伙伴交流和指正。app

相关文章
相关标签/搜索