参考zf2的EventManager,结合实际项目中的需要写了一个简易的EventManager,主要功能有:
- 订阅者模式;
- 拦截器;
- 事件驱动
具体概念就不介绍了,先来看看模块中的几个类或接口。
EventManager是核心模块,主要负责为监听事件,添加拦截器,触发事件,下面看一个例子:
<?php require 'EventManager.php'; $em = new EventManager(); $em->attach('start', function ($e) { printf('the parameter is %s', json_encode($e)); }); $params = array('foo' => 'bar', 'baz' => 'bat'); $em->trigger('start', $params);
输出结果为:the parameter is {"foo":"bar","baz":"bat"}
attach方法的原型为:
/** * attach a listener to an event * * @param $event string|array * @param $callback callable * @param $priority int */ public function attach($event,$callback,$priority=1) { if(is_array($event)) { foreach($event as $name) { $this->attach($name,$callback,$priority); } return; } if(!$this->events[$event]) $this->events[$event] = array(); if(!$this->events[$event][self::LISTENER]) $this->events[$event][self::LISTENER] = new SplPriorityQueue(); $listener = new Listener($event,$callback,intval($priority)); $this->events[$event][self::LISTENER]->insert($listener,$priority); }
三个参数分别为:
- 需要监听的事件名,可以是多个事件名组成的数组,事件名可以含有通配符;
- 监听器,任何合法的PHP回调都能作为监听器;
- 优先级,一个事件有多个监听器时优先级高的监听器先被触发。
InterceptorInterface接口
定义了拦截器需要实现的两个方法:before和after,before方法会先于监听器调用,after方法会在最后被调用,例子如下:
<?php class Interceptor implements InterceptorInterface { public function before($e = null) { printf('before '); } public function after($e = null) { printf('after '); } } require 'EventManager.php'; $em = new EventManager(); $em->attach('start', function ($e) { printf('start '); }); $em->attach('sta*', function ($e) { printf('sta* '); }, 3); $em->intercept('start', new Interceptor()); $em->trigger('start');
输出结果为:before sta* start after
另外还有Listener类和StaticEventManager,后者是一个全局的EventManager,具体实现可查看代码。
<?php interface InterceptorInterface { public function before(); public function after(); } class Listener { protected $event = null; protected $callback = null; protected $priority = 1; public function __CONSTRUCT($event, $callback, $priority) { $this->event = $event; $this->callback = $callback; $this->priority = $priority; } public function setEvent($event) { $this->event = $event; } public function getEvent() { return $this->event; } public function setCallBack($callback) { $this->callback = $callback; } public function getCallBack() { return $this->callback; } public function setPriority($priority) { $this->priority = $priority; } public function getPriority() { return $this->priority; } } class StaticEventManager { protected static $instance = null; protected function __CONSTRUCT() { } static public function ins() { if (self::$instance === null) { self::$instance = new EventManager(); } return self::$instance; } } class EventManager { /** * type */ const LISTENER = 0; const INTERCEPTOR = 1; /** * Subscribed events and their listeners and interceptors */ protected $events = array(); /** * intercept the event with an interceptor * * @param $event string|array * @param $interceptor InterceptorInterface */ public function intercept($event, InterceptorInterface $interceptor) { if (is_array($event)) { foreach ($event as $name) { $this->Intercept($name, $interceptor); } return; } if (!isset($this->events[$event])) $this->events[$event] = array(); if (!isset($this->events[$event][self::INTERCEPTOR])) $this->events[$event][self::INTERCEPTOR] = array(); $this->events[$event][self::INTERCEPTOR][] = $interceptor; } /** * attach a listener to an event * * @param $event string|array * @param $callback callable * @param $priority int */ public function attach($event, $callback, $priority = 1) { if (is_array($event)) { foreach ($event as $name) { $this->attach($name, $callback, $priority); } return; } if (!isset($this->events[$event])) $this->events[$event] = array(); if (!isset($this->events[$event][self::LISTENER])) $this->events[$event][self::LISTENER] = new SplPriorityQueue(); $listener = new Listener($event, $callback, intval($priority)); $this->events[$event][self::LISTENER]->insert($listener, $priority); } /** * trigger listeners of an event * * @param $event string|array * @param $params */ public function trigger($event, $params = null) { if (is_array($event)) { foreach ($event as $name) { $this->trigger($name, $callback, $priority); } return; } $matchEvents = $this->getMatchEvents($event); $interceptors = array(); $listeners = new SplPriorityQueue(); foreach ($matchEvents as $e) { $interceptors = array_merge($interceptors, $this->getInterceptors($e)); $this->insertListeners($listeners, $this->getListeners($e)); } foreach ($interceptors as $interceptor) { $interceptor->before($params); } $this->triggerListeners($listeners, $params); foreach ($interceptors as $interceptor) { $interceptor->after($params); } } /** * retrieve all registered events * * @return array */ public function getEvents() { return array_keys($this->events); } /** * retrieve all matched events for a given event * * @return array */ public function getMatchEvents($event) { $allEvents = $this->getEvents(); $matchEvents = array(); foreach ($allEvents as $key) { if (preg_match('/' . $key . '/i', $event)) { $matchEvents[] = $key; } } return $matchEvents; } /** * retrieve all listeners for a given event * * @param $event string * @return SplPriorityQueue */ public function getListeners($event) { $listeners = new SplPriorityQueue(); if ($this->events[$event][self::LISTENER]) $listeners = $this->events[$event][self::LISTENER]; return $listeners; } /** * retrieve all interceptors for a given event * * @param $event string * @return array */ protected function getInterceptors($event) { $interceptors = array(); if (isset($this->events[$event][self::INTERCEPTOR])) $interceptors = $this->events[$event][self::INTERCEPTOR]; return $interceptors; } /** * Trigger listeners * * @param $listeners array * @param $params */ protected function triggerListeners($listeners, $params = null) { foreach ($listeners as $listener) { call_user_func($listener->getCallBack(), $params); } } /** * Add listeners to the master queue of listeners * * @param PriorityQueue $masterListeners * @param PriorityQueue $listeners * @return void */ protected function insertListeners($masterListeners, $listeners) { if (!count($listeners)) { return; } foreach ($listeners as $listener) { $priority = $listener->getPriority(); if (null === $priority) { $priority = 1; } $masterListeners->insert($listener, $priority); } } }
欢迎交流,如果您有更好的建议,请不吝赐教。