引言
考慮這樣一個(gè)問題,現(xiàn)在你想給為你的項(xiàng)目提供一個(gè)插件系統(tǒng),插件可以添加一些方法,或者在某些方法執(zhí)行之前或者之后做些事情,而不干擾其他插件。要實(shí)現(xiàn)這個(gè)系統(tǒng),簡(jiǎn)單的單繼承不是個(gè)好辦法,即使多繼承在PHP中是可能的,他也有與生俱來的缺點(diǎn)(多繼承不太了解,感覺挺操蛋的)。
Symfony EventDispatcher以一個(gè)簡(jiǎn)單有效的方式實(shí)現(xiàn)了中介者模式,事件分發(fā)器就是那個(gè)中介,讓系統(tǒng)和插件不會(huì)耦合在一起,這讓上面的插件系統(tǒng)成為可能,而且他會(huì)讓你的項(xiàng)目可擴(kuò)展性更好。
上面的話,翻譯自Symfony官方文檔片段
系統(tǒng)剖析
事件存儲(chǔ)
上面這張圖是分析Symfony EventDispatcher組件源碼得出來的,可以看到事件在系統(tǒng)中是如何存儲(chǔ)的
這里面將事件存儲(chǔ)了兩遍,用來加入優(yōu)先級(jí)priority的概念,存如的時(shí)候放入上圖中上面的結(jié)構(gòu)中,取出時(shí)候從上圖中下面的結(jié)構(gòu)中拿出來,相同的事件名稱可以有不同的優(yōu)先級(jí),優(yōu)先級(jí)越高的事件優(yōu)先觸發(fā),優(yōu)先級(jí)相同的時(shí)候,先插入的事件優(yōu)先觸發(fā)。
排序事件(上圖中下面的結(jié)構(gòu))在插入事件的時(shí)候不會(huì)構(gòu)建,而是當(dāng)取出事件的時(shí)候會(huì)生成排好序的事件,當(dāng)相同的事件名中插入新的事件或刪除某個(gè)事件的時(shí)候,會(huì)刪除對(duì)應(yīng)的排好序的事件名,后面用到的時(shí)候重新構(gòu)建
執(zhí)行事件的時(shí)候,會(huì)獲取對(duì)應(yīng)事件名排好序的linster列表,按照順序依次執(zhí)行。
事件執(zhí)行
如上圖所示,當(dāng)觸發(fā)某個(gè)時(shí)間的時(shí)候,該事件名下面如果監(jiān)聽了多個(gè)觸發(fā)動(dòng)作,他們會(huì)按照優(yōu)先級(jí)、注冊(cè)順序依次觸發(fā),觸發(fā)動(dòng)作一般是一個(gè)可執(zhí)行的“實(shí)例”(不管是類還是函數(shù),必須可以通過call_user_func_array調(diào)用),可以傳入三個(gè)參數(shù),第一個(gè)參數(shù)(必須)是一個(gè)Event實(shí)例,第二個(gè)是觸發(fā)的事件名,第三個(gè)是事件分發(fā)器實(shí)例。第一個(gè)參數(shù)會(huì)控制事件是否在該事件名下的所有觸發(fā)動(dòng)作之間繼續(xù)傳遞,比如上面的linstener_2里面將Event.propagationStopped設(shè)置為true,執(zhí)行完linstener_2后,事件就會(huì)停止傳播,linstener_2后面的動(dòng)作不會(huì)觸發(fā)。
除此之外,Event實(shí)例中還可以保存其他必要的信息,以便linstener觸發(fā)執(zhí)行的時(shí)候,獲取額外的信息。
事件訂閱者
事件訂閱者(Event subscriber),告訴dispathcer實(shí)例,他要訂閱的所有事件,不用一個(gè)個(gè)通過dispathcer實(shí)例去注冊(cè)。事件訂閱者是一個(gè)PHP類,他可以告訴dispathcer他要訂閱的具體的事件。
好處:
關(guān)注的事件不用一個(gè)個(gè)去注冊(cè)。 取消關(guān)注的事件不用一個(gè)個(gè)去移除注冊(cè)。訂閱者內(nèi)部關(guān)注的事件是一個(gè)整體,要么全部關(guān)注要么全部不關(guān)注
實(shí)例
普通栗子
include "vendor/autoload.php"; use SymfonyComponentEventDispatcherEventDispatcher; use SymfonyComponentEventDispatcherEvent; class UserEvent extends Event { public function name() { return "Cartman"; } public function age() { return "24"; } } $dispatcher = new EventDispatcher(); $dispatcher->addListener("user.name", function($event, $eventName, $dispatcher){ echo "My name is Cartmann"; }); $dispatcher->addListener("user.name", function($event, $eventName, $dispatcher){ echo "My name is {$event->name()} from Event instancen"; }, 10); $dispatcher->addListener("user.age", function($event, $eventName, $dispatcher){ echo "My age is 24n"; }, 10); $dispatcher->addListener("user.age", function($event, $eventName, $dispatcher){ echo "My age is {$event->age()} from Event instancen"; }, -10); $dispatcher->dispatch("user.name", new UserEvent()); $dispatcher->dispatch("user.age", new UserEvent());
上面的例子輸出
My name is Cartman from Event instance My name is Cartman My age is 24 My age is 24 from Event instance
事件訂閱者栗子
通過Subscriber注冊(cè)事件
include "vendor/autoload.php"; use SymfonyComponentEventDispatcherEventDispatcher; use SymfonyComponentEventDispatcherEvent; use SymfonyComponentEventDispatcherEventSubscriberInterface; class BookEvent extends Event { public $name = self::class; } class BookSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents() { return [ "chinese.name" => "chineseNameShow", "english.name" => [ ["englishNameShow", -10], ["englishNameAFter", 10], ], "math.name" => ["mathNameShow", 100] ]; } public function chineseNameShow(Event $event) { echo "我是漢語書籍n"; } public function englishNameShow(Event $event) { echo "我是英文書籍n"; } public function englishNameAFter(Event $event) { echo "我是展示之后的英文書籍[來自于Event實(shí)例{$event->name}]n"; } public function mathNameShow(Event $event) { echo "我是展示的數(shù)學(xué)書籍n"; } } $dispatcher = new EventDispatcher(); $subscriber = new BookSubscriber(); $dispatcher->addSubscriber($subscriber); $dispatcher->dispatch("english.name", new BookEvent()); $dispatcher->dispatch("chinese.name"); $dispatcher->removeSubscriber($subscriber); $dispatcher->dispatch("math.name");
輸出為內(nèi)容:
我是展示之后的英文書籍[來自于Event實(shí)例BookEvent] 我是英文書籍 我是漢語書籍
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時(shí)也希望多多支持綠夏網(wǎng)!