你們好,這篇文章將經過我在實際開發工做中的例子,來介紹Symfony的EventDispatcher組件的使用及實現原理。php
這個組件在實際開發過程當中很是的有用,它可以使代碼的業務邏輯變的很是清晰,增長代碼的複用性,代碼的耦合性也大大下降。html
具體的介紹你們能夠查看官方的文檔,下面是文檔地址。this
文檔地址spa
# 初始時,添加監聽器 $dispatcher = new EventDispatcher(); $disptacher->addSubscriber(new BIReportSubscriber()); // BI上報功能 $disptacher->addSubscriber(new MediaPlayerSubscriber()); // 維護播放器信息統一
Symfony\Component\EventDispatcher\EventDispatcher
class BIReportSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents () { // 監聽的不一樣事件,當事件觸發時,會調用 onResponse 方法 return [ MusicResponseEvent::NAME => 'onResponse', ChildrenResponseEvent::NAME => 'onResponse', FmResponseEvent::NAME => 'onResponse', NewsResponseEvent::NAME => 'onResponse', ]; } public function onResponse(AResponseEvent $event) { /* * 一些具體的業務邏輯 * 進行 BI 上報 */ }
class MediaPlayerSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents () { return [ MusicResponseEvent::NAME => 'onResponse', FmResponseEvent::NAME => 'onResponse', ChildrenResponseEvent::NAME => 'onResponse', NewsResponseEvent::NAME => 'onResponse', ]; } public function onResponse(AResponseEvent $event) { /* * 一些具體的業務邏輯 * 維護播放器信息統一 */ }
getSubscribedEvents
方法,完成事件的綁定。當事件觸發時,dispatcher 會調用綁定的方法,並將拋出的事件當作參數傳入。onResponse
能夠是任何名字。onResponse
方法中,經過 $event
獲取要操做的對象。class FmResponseEvent extends Event { const NAME = 'fm.response'; // 事件名,事件的惟一標識 protected $request; // 在監聽器裏要操做的對象 protected $response; // 在監聽器裏要操做的對象 public function __construct (Request $request, Response $response) { $this->request = $request; $this->response = $response; } /** * @return Request */ public function getRequest() { return $this->request; } /** * @return Response */ public function getResponse() { return $this->response; } }
Symfony\Component\EventDispatcher\Event
$request 和 $response
對象,因此本事件包含這兩個類的對象。$event = new FmResponseEvent($request, $response); $dispatcher->dispatch($event::NAME, $event);
dispathcer
會按照優先級,依次執行訂閱器中事件綁定的方法class EventDispatcher implements EventDispatcherInterface { private $listeners = array(); private $sorted = array(); /** * 觸發事件 */ public function dispatch($eventName, Event $event) { if ($listeners = $this->getListeners($eventName)) { $this->doDispatch($listeners, $eventName, $event); } return $event; } /** * 根據事件名,搜索監聽器 */ public function getListeners($eventName) { if (empty($this->listeners[$eventName])) { return array(); } if (!isset($this->sorted[$eventName])) { $this->sortListeners($eventName); } return $this->sorted[$eventName]; } /** * 換優先級將監聽器排序 * @param string $eventName */ private function sortListeners($eventName) { krsort($this->listeners[$eventName]); $this->sorted[$eventName] = array(); foreach ($this->listeners[$eventName] as $priority => $listeners) { foreach ($listeners as $k => $listener) { if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) { $listener[0] = $listener[0](); $this->listeners[$eventName][$priority][$k] = $listener; } $this->sorted[$eventName][] = $listener; } } } protected function doDispatch($listeners, $eventName, Event $event) { foreach ($listeners as $listener) { if ($event->isPropagationStopped()) { break; } \call_user_func($listener, $event, $eventName, $this); } /** * 添加訂閱器 */ public function addSubscriber(EventSubscriberInterface $subscriber) { foreach ($subscriber->getSubscribedEvents() as $eventName => $params) { if (is_string($params)) { $this->addListener($eventName, array($subscriber, $params)); } elseif (is_string($params[0])) { $this->addListener($eventName, array($subscriber, $params[0]), isset($params[1]) ? $params[1] : 0); } else { foreach ($params as $listener) { $this->addListener($eventName, array($subscriber, $listener[0]), isset($listener[1]) ? $listener[1] : 0); } } } } public function addListener($eventName, $listener, $priority = 0) { $this->listeners[$eventName][$priority][] = $listener; unset($this->sorted[$eventName]); } }