Event mechanism principle and usage analysis of Yii framework component

Time:2021-1-27

This paper illustrates the principle and usage of event mechanism of Yii framework component. The details are as follows:

Before deeply analyzing the operation of Yii, let’s take a look at a very important mechanism event in the framework of Yii.

Explanation of component events in Yii official reference document:

=======================================================================

Component events are special properties that use methods called event handlers as their values. Attaching (assigning) a method to an event causes the method to be called automatically where the event is called. Therefore, the behavior of a component may be modified in an unforeseen way during component development.

Component events are defined in a named way that starts with on. Just as properties are named by getter / setter methods, event names are case insensitive. The following code defines an onclicked event:


public function onClicked($event)
{
  $this->raiseEvent('onClicked', $event);
}

Here $event as an event parameter is an instance of cevent or its subclass.

We can attach a method to this event as follows:


$component->onClicked=$callback;

The $callback here points to a valid PHP callback. It can be a global function or a method in a class. If it is the latter, it must be provided as an array: array ($object, ‘methodname’)

The structure of the event handle is as follows:


function methodName($event)
{
  ......
}

Here $event is the parameter that describes the event (it comes from the raiseevent() call). The $event parameter is an instance of cevent or its subclass. At the very least, it contains information about who triggered the event.

Starting from version 1.0.10, the event handle can also be an anonymous function supported after PHP 5.3. For example,


$component->onClicked=function($event) {
  ......
}

If we call onclicked () now, the onclicked event will be triggered (in onclicked ()), and the attached event handle will be called automatically.

An event can bind multiple handles. When an event is triggered, these handles are executed in the order in which they were bound to the event. If the handle decides to organize subsequent handles to be executed, it can set $event – > handled to true.

=======================================================================

Starting from this sentence, “we can attach a method to this event”, the reader may not know what it means, so take a look at the source code of ccomponent

/**
   * Raises an event.
   * This method represents the happening of an event. It invokes
   * all attached handlers for the event.
   * @param string the event name
   * @param CEvent the event parameter
   * @throws CException if the event is undefined or an event handler is invalid.
   */
  public function raiseEvent($name,$event)
{
  //Lowercase event name
    $name=strtolower($name);
    //First check whether the member variable has an event named after it
    if(isset($this->_e[$name]))
    {
      //If so, this member holds each event handler
      //Save as an array
      foreach($this->_e[$name] as $handler)
      {
        //If the event handler is a string, it is a global function
        if(is_string($handler))
          call_user_func($handler,$event);
        //If not, it could be an array that contains an object and method name
        //Reference http://php.net/manual/en/function.is-callable.php
        else if(is_callable($handler,true))
        {
          // an array: 0 - object, 1 - method name
          list($object,$method)=$handler;
          //If the object is an object name
          if(is_string($object)) // static method call
            call_user_func($handler,$event);
          //Determine whether the object has a method to call
          else if(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
          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 you want to stop the loop, get the handler of the event
//Then you need to set event handled to true
        if(($event instanceof CEvent) && $event->handled)
          return;
      }
    }
    else if(YII_DEBUG && !$this->hasEvent($name))
      throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.',
        array('{class}'=>get_class($this), '{event}'=>$name)));
    //If_ It doesn't matter if you don't have this member in E
  }

Let’s take a look at the cevent code( CComponent.php ):


class CEvent extends CComponent
{
  /**
   * @var object the sender of this event
   */
  public $sender;
  /**
   * @var boolean whether the event is handled. Defaults to false.
   * When a handler sets this true, the rest uninvoked handlers will not be invoked anymore.
   */
  public $handled=false;

  /**
   * Constructor.
   * @param mixed sender of the event
   */
  public function __construct($sender=null)
  {
    $this->sender=$sender;
  }
}

Cevent only contains two variables $sender to record the event trigger, and $handled indicates whether the event has been “resolved”.

Next, let’s look at how to register an event handler for a component

/**
   * Attaches an event handler to an event.
   *
   * An event handler must be a valid PHP callback, i.e., a string referring to
   * a global function name, or an array containing two elements with
   * the first element being an object and the second element a method name
   * of the object.
   *
   * An event handler must be defined with the following signature,
   * <pre>
   * function handlerName($event) {}
   * </pre>
   * where $event includes parameters associated with the event.
   *
   * This is a convenient method of attaching a handler to an event.
   * It is equivalent to the following code:
   * <pre>
   * $component->getEventHandlers($eventName)->add($eventHandler);
   * </pre>
   *
   * Using {@link getEventHandlers}, one can also specify the excution order
   * of multiple handlers attaching to the same event. For example:
   * <pre>
   * $component->getEventHandlers($eventName)->insertAt(0,$eventHandler);
   * </pre>
   * makes the handler to be invoked first.
   *
   * @param string the event name
   * @param callback the event handler
   * @throws CException if the event is not defined
   * @see detachEventHandler
   */
  public function attachEventHandler($name,$handler)
  {
    $this->getEventHandlers($name)->add($handler);
  }
  /**
   * Returns the list of attached event handlers for an event.
   * @param string the event name
   * @return CList list of attached event handlers for the event
   * @throws CException if the event is not defined
   */
  public function getEventHandlers($name)
  {
    if($this->hasEvent($name))
    {
      $name=strtolower($name);
      if(!isset($this->_e[$name]))
        //Create a new Clist processor to store events
        $this->_e[$name]=new CList;
      return $this->_e[$name];
    }
    else
      throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.',
        array('{class}'=>get_class($this), '{event}'=>$name)));
}

From this, we can see that first, we get the event processor object, if not, we use Clist (a linked list implemented by Yii) to create it, and then add the event processor into this object. In this way, we can traverse all the event processors for processing during raiseevent. It’s a bit similar to that when multiple click event processors are registered in jQuery, when the When an event is triggered, the previously registered event handlers are called in sequence.

For more information about Yii, readers who are interested in it can see the following topics: Yii framework introduction and common skills summary, PHP excellent development framework summary, smart template introduction basic course, PHP object-oriented programming introduction course, PHP string usage summary, PHP + MySQL database operation introduction course and PHP common database operation introduction course Summary of writing skills

I hope this article will be helpful to the PHP Programming Based on Yii framework.