美文网首页
yii浅析(三)

yii浅析(三)

作者: 柏树_Jeff | 来源:发表于2016-01-19 11:21 被阅读218次

    整个应用是基于下面这句代码运行起来的:

    Yii::createWebApplication($env->configWeb)->run();
    

    是的,就是这个run方法。我们在CWebApplication中找到run方法的实现:

    public function run(){   
      //应用跑起来之前     
      if($this->hasEventHandler('onBeginRequest'))      
          $this->onBeginRequest(new CEvent($this));   
      //最后运行的方法   -- 1
      register_shutdown_function(array($this,'end'),0,false);   
      //处理请求
      $this->processRequest();   
    
      //处理请求结束之后 -- 2(2的运行顺序在1之前)
      if($this->hasEventHandler('onEndRequest'))      
          $this->onEndRequest(new CEvent($this));
    }
    

    接下来我们应该来说明这句代码:

    $this->hasEventHandler('onBeginRequest')
    

    不过在解释它之前,我们需要理解一下yii的event机制。

    Yii的event机制

    YII的事件机制,是其比较独特之处,合理使用好事件机制,会使各个组件之间的耦合更为松散,利于团体协作开发。

    何时需要使用事件,如何给事件绑定事件处理函数,以及如何触发事件,与其它语言是有较大的差别的。例如Javascript中,可以使用

    $(‘#id’).on("click",function() {});
    

    方式给DOM元素绑定处理函数,当DOM元素上发生指定的事件(如click)时,将自动执行设定的函数。

    但是PHP是服务器端的脚本语言,就不存在自动触发事件之说,所以和Javascript对比,YII中的事件是需要手动触发的。一般来说,要实现YII组件的事件机制,需要以下几步:

    1. 定义事件名称,其实就是级组件定义一个on开头的方法,其中的代码是固定的,如:
      public function onBeginRequest($event){
      $this->raiseEvent('onBeginRequest',$event);
    }
    

    即函数名与事件名是一致的。此步的作用就是将绑定在此事件上的处理函数逐个执行。写这一系列的播客,算是一个整理,所以我写细一点,现在把raiseEvent方法的代码贴出来。

    /** * Raises an event. 
        * This method represents the happening of an event. It invokes 
        * all attached handlers for the event. 
        * @param string $name the event name 
        * @param CEvent $event the event parameter 
        * @throws CException if the event is undefined or an event handler is invalid. 
    */
        
        public function raiseEvent($name,$event){   
                  $name=strtolower($name);   
                  //_e这个数组用来存所有事件信息
                  if(isset($this->_e[$name]))   {      
                        foreach($this->_e[$name] as $handler)  {         
                            if(is_string($handler)) 
                               call_user_func($handler,$event);             
                            elseif(is_callable($handler,true)){  
                                      if(is_array($handler)){               
                                          // an array: 0 - object, 1 - method name    
                                         list($object,$method)=$handler;     
                                         if(is_string($object)) // static method call  
                                            call_user_func($handler,$event);  
                                         elseif(method_exists($object,$method))         
                                             $object->$method($event);               
                                         else                  
                                              throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".',   array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>$handler[1])));           
                                       }            
                                        else // PHP 5.3: anonymous function  
                                             call_user_func($handler,$event);         
                            }         
                            else            
                                throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".', array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>gettype($handler))));         
                          // stop further handling if param.handled is set true  
                            if(($event instanceof CEvent) && $event->handled)  
                                return;     
                       }  
                   }   elseif(YII_DEBUG && !$this->hasEvent($name))      
                        throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.',         array('{class}'=>get_class($this), '{event}'=>$name)));
      }
    

    2 . 给组件对象绑定事件处理函数

    $component->attachEventHandler($name, $handler);
    $component->onBeginRequest = $handler ;
    

    yii支持一个事件绑定多个回调函数,上述的两个方法都会在已有的事件上增加新的回调函数,而不会覆盖已有回调函数。

    $handler即是一个PHP回调函数,关于回调函数的形式,本文的最后会附带说明。
    如CLogRouter组件的init事件中,有以下代码:

    Yii::app()->attachEventHandler('onEndRequest',array($this,'processLogs'));
    

    这就是给CApplication对象的onEndRequest绑定了CLogRouter::processLogs()回调函数。而CApplication组件确实存在名为onEndRequest的方法(即onEndRequest事件),它之中的代码就是激活了相应的回调函数,即CLogRouter::processLogs()方法。所以从这里可以得出,日志的记录其实是发生在CApplication组件的正常退出时。

    1. 在需要触发事件的时候,直接激活组件的事件,即调用事件即可,如:
      比如CApplication组件的run方法中:
    if($this->hasEventHandler('onBeginRequest'))
        $this->onBeginRequest(new CEvent($this));
    

    这样即触发了事件处理函数。如果没有第一行的判断,那么在调试模式下(YII_DEBUG常量被定义为true),会抛出异常,而在非调试模式下(YII_DEBUG常量定义为false或没有定义YII_DEBUG常量),则不会产生任何异常。

    回调函数的形式:

    1. 普通全局函数(内置的或用户自定义的)
    call_user_func(‘print’, $str);
    
    1. 类的静态方法,使用数组形式传递
    call_user_func(array(‘className’, ‘print’),  $str );
    
    1. 对象方法,使用数组形式传递
    $obj = new className();
    call_user_func(array($obj, ‘print’),  $str );
    
    1. 匿名方法,类似javascript的匿名函数
    call_user_func(function($i){echo $i++;},4);
    

    或使用以下形式:

    $s = function($i) {
        echo $i++;
    };
    call_user_func($s,4);
    

    总结: 关于Yii的事件机制其实就是提供了一种用于解耦的方式,在需要调用event的地方之前,只要你提供了事件的实现并注册在之后的地方需要的时候即可调用。

    相关文章

      网友评论

          本文标题:yii浅析(三)

          本文链接:https://www.haomeiwen.com/subject/iiikkttx.html