Laravel 的事件提供了一個簡單的觀察者實現,能夠訂閱和監聽應用中發生的各種事件。事件機制是一種很好的應用解耦方式,因為一個事件可以擁有多個互不依賴的監聽器。laravel 中事件系統由兩部分構成,一個是事件的名稱,事件的名稱可以是個字符串,例如 event.email,也可以是一個事件類,例如 App/Events/OrderShipped;另一個是事件的 監聽器listener,可以是一個閉包,還可以是監聽類,例如 App/Listeners/SendShipmentNotification。
我們還是通過官方文檔里給出的這個例子來向下分析事件系統的源碼實現,不過在應用注冊事件和監聽器之前,Laravel在應用啟動時會先注冊處理事件用的events服務。
Laravel注冊事件服務Laravel應用在創建時注冊的基礎服務里就有Event服務
namespace Illuminate/Foundation;html' target='_blank'>class Application extends Container implements ... public function __construct($basePath = null) $this- registerBaseServiceProviders(); protected function registerBaseServiceProviders() $this- register(new EventServiceProvider($this)); $this- register(new LogServiceProvider($this)); $this- register(new RoutingServiceProvider($this));}
其中的 EventServiceProvider 是 /Illuminate/Events/EventServiceProvider
public function register() $this- app- singleton( events , function ($app) { return (new Dispatcher($app))- setQueueResolver(function () use ($app) { return $app- make(QueueFactoryContract::class);}
Illuminate/Events/Dispatcher 就是 events服務真正的實現類,而Event門面時events服務的靜態代理,事件系統相關的方法都是由Illuminate/Events/Dispatcher來提供的。
應用中注冊事件和監聽我們還是通過官方文檔里給出的這個例子來向下分析事件系統的源碼實現,注冊事件和監聽器有兩種方法,App/Providers/EventServiceProvider 有個 listen 數組包含所有的事件(鍵)以及事件對應的監聽器(值)來注冊所有的事件監聽器,可以靈活地根據需求來添加事件。
/** * 應用程序的事件監聽器映射。 * @var arrayprotected $listen = [ App/Events/OrderShipped = [ App/Listeners/SendShipmentNotification ,];
也可以在 App/Providers/EventServiceProvider 類的 boot 方法中注冊基于事件的閉包。
/** * 注冊應用程序中的任何其他事件。 * @return voidpublic function boot() parent::boot(); Event::listen( event.name , function ($foo, $bar) {}
可以看到/App/Providers/EventProvider類的主要工作就是注冊應用中的事件,這個注冊類的主要作用是事件系統的啟動,這個類繼承自 /Illuminate/Foundation/Support/Providers/EventServiceProvide。
我們在將服務提供器的時候說過,Laravel應用在注冊完所有的服務后會通過/Illuminate/Foundation/Bootstrap/BootProviders調用所有Provider的boot方法來啟動這些服務,所以Laravel應用中事件和監聽器的注冊就發生在 /Illuminate/Foundation/Support/Providers/EventServiceProvide類的boot方法中,我們來看一下:
public function boot() foreach ($this- listens() as $event = $listeners) { foreach ($listeners as $listener) { Event::listen($event, $listener); foreach ($this- subscribe as $subscriber) { Event::subscribe($subscriber);}
可以看到事件系統的啟動是通過events服務的監聽和訂閱方法來創建事件與對應的監聽器還有系統里的事件訂閱者。
namespace Illuminate/Events;class Dispatcher implements DispatcherContract public function listen($events, $listener) foreach ((array) $events as $event) { if (Str::contains($event, * )) { $this- setupWildcardListen($event, $listener); } else { $this- listeners[$event][] = $this- makeListener($listener); protected function setupWildcardListen($event, $listener) $this- wildcards[$event][] = $this- makeListener($listener, true);}
對于包含通配符的事件名,會被統一放入 wildcards 數組中,makeListener是用來創建事件對應的listener的:
class Dispatcher implements DispatcherContract public function makeListener($listener, $wildcard = false) if (is_string($listener)) {//如果是監聽器是類,去創建監聽類 return $this- createClassListener($listener, $wildcard); return function ($event, $payload) use ($listener, $wildcard) { if ($wildcard) { return $listener($event, $payload); } else { return $listener(...array_values($payload));}
創建listener的時候,會判斷監聽對象是監聽類還是閉包函數。
對于閉包監聽來說,makeListener 會再包裝一層返回一個閉包函數作為事件的監聽者。
對于監聽類來說,會繼續通過 createClassListener 來創建監聽者
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。
新聞熱點
疑難解答