淺析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

相關文章
相關標籤/搜索