php EventManager Module


zf 2の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); 
    }                                                                       

    3つのパラメータは、次のとおりです.
  • は、複数のイベント名からなる配列であってもよく、イベント名にワイルドカードを含むことができるリスニングを必要とするイベント名である.
  • リスナー、いかなる合法的なPHPコールバックもリスナーとすることができる.
  • 優先度は、1つのイベントに複数のListenerがある場合に優先度の高いListenerが先にトリガーされます.

  • InterceptorInterfaceインタフェース
    ブロッカーが実装する必要がある2つの方法を定義します: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);
            }
        }
    }

    交流を歓迎します.もっと良いアドバイスがあれば、教えてください.