This article mainly introduces the event mechanism in the PHP Yii Framework. it describes Yii event processors and important knowledge about binding event processing functions to component objects. For more information, see
Event
Events can inject custom code to specific execution points in existing code. Attaches custom code to an event. when this event is triggered, the code is automatically executed. For example, a messageSent event can be triggered when a mail program object successfully sends a message. To track successfully sent messages, you can append the corresponding tracing code to the messageSent event.
Yii introduces a base class named yii \ base \ Component to support events. If a class needs to trigger an event, it should inherit yii \ base \ Component or its subclass.
Yii event mechanism
YII's event mechanism is unique. a proper use of the event mechanism will make the coupling between components more loose and facilitate group collaborative development.
When to use events, how to bind event processing functions to events, and how to trigger events are significantly different from other languages. For example, in Javascript, you can use
$(‘#id').on("click",function() {});
Method to bind a handler to the DOM element. when a specified event (such as click) occurs on the DOM element, the set function is automatically executed.
However, PHP is a script language on the server and there is no automatic trigger event. Therefore, compared with Javascript, events in YII need to be manually triggered. Generally, the following steps are required to implement the event mechanism of the YII component:
Defining the event name is actually a method for a level component to define the beginning of an on. The code is fixed, such:
public function onBeginRequest($event){ $this->raiseEvent('onBeginRequest',$event);}
That is, the function name is consistent with the event name. This step is to run the processing functions bound to this event one by one. Writing this series of podcasts is an arrangement, so I will write a little more details. now I will paste the code of the raiseEvent method.
/*** 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 ); // The _ e array is used to store all event information 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),' {even T} '=> $ 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 )));}
Event Handlers)
The event processor is a PHP callback function that is executed when the event appended to it is triggered. You can use one of the following callback functions:
- PHP global functions specified in string form, such as 'trim ';
- Object method specified in the form of an array of object and method names, such as [$ object, $ method];
- Static class methods specified in the form of an array of class names and method names, such as [$ class, $ method];
- Anonymous functions, such as function ($ event ){...}.
The event processor format is:
Function ($ event) {// $ event is an object of yii \ base \ Event or its subclass}
With the $ event parameter, the event processor obtains the following event information:
- Yii \ base \ Event: name: Event name
- Yii \ base \ Event: sender: the object that calls the trigger () method
- Yii \ base \ Event: data: The data imported when an Event processor is attached. it is null by default.
Additional event processor
Call the yii \ base \ Component: on () method to attach the processor to the event. For example:
$ Foo = new Foo; // The processor is a global function $ foo-> on (Foo: EVENT_HELLO, 'function _ name '); // The processor is the object method $ foo-> on (Foo: EVENT_HELLO, [$ object, 'methodname']); // The processor is a static class method $ foo-> on (Foo: EVENT_HELLO, ['app \ components \ bar', 'methodname']); // The processor is an anonymous function $ foo-> on (Foo: EVENT_HELLO, function ($ event) {// event processing logic }); when an event processor is attached, additional data can be provided as the third parameter of the yii \ base \ Component: on () method. Data can be used by the processor when an event is triggered and the processor is called. For example: // when an event is triggered, the following code displays "abc" // because $ event-> data includes the data passed to the "on" method $ foo-> on (Foo :: EVENT_HELLO, function ($ event) {echo $ event-> data;}, 'ABC ');
Event Processor sequence
You can attach one or more processors to an event. When an event is triggered, the added processors are called in the order of appending. If a processor needs to stop calling the processor, you can set the $ event parameter's [yii \ base \ Event: handled] attribute to true, as shown below:
$foo->on(Foo::EVENT_HELLO, function ($event) { $event->handled = true;});
By default, the new event processor is placed at the end of the existing processor queue. Therefore, this processor will call the last one when the event is triggered. Inserting a new processor at the beginning of the processor queue will make the processor call first. you can pass the fourth parameter $ append as false and call the yii \ base \ Component: on () method for implementation:
$ Foo-> on (Foo: EVENT_HELLO, function ($ event) {// This processor will be inserted into the first processor queue...}, $ data, false );
Trigger Event
An event is triggered by calling the yii \ base \ Component: trigger () method. this method must pass the event name and an event object to pass parameters to the event processor. For example:
namespace app\components;use yii\base\Component;use yii\base\Event;class Foo extends Component{ const EVENT_HELLO = 'hello'; public function bar() { $this->trigger(self::EVENT_HELLO); }}
When bar () is called, the above code triggers an event named hello.
Tip: We recommend that you use a class constant to indicate the event name. In the above example, the constant EVENT_HELLO is used to represent hello. There are two benefits. First, it prevents spelling errors and supports automatic IDE completion. Second, you only need to check the constant declaration to understand what events a class supports.
Sometimes you want to pass some additional information to the event processor when an event is triggered. For example, the email program needs to transmit message information to the processor of the messageSent event so that the processor can understand which messages are sent. Therefore, you can provide an Event object as the second parameter of the yii \ base \ Component: trigger () method. This Event object must be an instance of the yii \ base \ Event class or its subclass. For example:
Namespace app \ components; use yii \ base \ Component; use yii \ base \ Event; class MessageEvent extends Event {public $ message ;} class Mailer extends Component {const EVENT_MESSAGE_SENT = 'messagesent'; public function send ($ message ){//... logic for sending $ message... $ event = new MessageEvent; $ event-> message = $ message; $ this-> trigger (self: EVENT_MESSAGE_SENT, $ event );}}
When the yii \ base \ Component: trigger () method is called, it calls all event processors attached to the naming event (the first parameter of the trigger method.
Remove event processor
Remove the processor from the event and call the yii \ base \ Component: off () method. For example:
// The processor is a global function $ foo-> off (Foo: EVENT_HELLO, 'function _ name'); // The processor is an object method $ foo-> off (Foo :: EVENT_HELLO, [$ object, 'methodname']); // The processor is a static class method $ foo-> off (Foo: EVENT_HELLO, ['app \ components \ bar ', 'methodname']); // The processor is an anonymous function $ foo-> off (Foo: EVENT_HELLO, $ anonymousFunction );
Note: When an anonymous function is appended to an event, do not try to remove it unless you store it somewhere. In the preceding example, the anonymous function is stored as the variable $ anonymousFunction.
Remove all event processors. simply call yii \ base \ Component: off () without the second parameter:
$foo->off(Foo::EVENT_HELLO);
Class-level event processor
The above section describes how to attach a processor to an event at the instance level. Sometimes all instances of a class, instead of a specified instance, want to respond to a triggered event, instead of appending an event processor to each instance, instead, append a processor at the class level by calling the static method yii \ base \ Event: on.
For example, an yii \ db \ BaseActiveRecord: EVENT_AFTER_INSERT event is triggered every time an activity Record object adds a new record to the database. To track the completion of new records for each activity Record object, write the following code:
use Yii;use yii\base\Event;use yii\db\ActiveRecord;Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) { Yii::trace(get_class($event->sender) . ' is inserted');});
The event processor executes the yii \ db \ BaseActiveRecord: EVENT_AFTER_INSERT event whenever an instance of yii \ db \ BaseActiveRecord or its subclass triggers the yii \ db \ BaseActiveRecord: EVENT_AFTER_INSERT event. In this processor, you can use $ event-> sender to obtain the object that triggers the event.
When an object triggers an event, it first calls the instance-level processor before calling the class-level processor.
You can call the static method yii \ base \ Event: trigger () to trigger a class-level Event. Class-level events are not associated with specific objects. Therefore, it will only cause calls by the class-level event processor. For example:
Use yii \ base \ Event; Event: on (Foo: className (), Foo: EVENT_HELLO, function ($ event) {echo $ event-> sender; // Display "app \ models \ Foo"}); Event: trigger (Foo: className (), Foo: EVENT_HELLO );
Note that in this case, $ event-> sender points to the class name of the trigger event rather than the object instance.
Note: Because the events triggered by class-level processor response classes and all instances of their subclasses must be used with caution, especially the underlying base classes, such as yii \ base \ Object.
To remove a class-level Event processor, you only need to call yii \ base \ Event: off (), for example:
// Remove $ handlerEvent: off (Foo: className (), Foo: EVENT_HELLO, $ handler); // remove all processor events for the Foo: EVENT_HELLO Event :: off (Foo: className (), Foo: EVENT_HELLO );
Global events
Global events are actually a trick based on the event mechanism described above. It requires a globally accessible Singleton, such as an application instance.
The trigger of an event does not call its own trigger () method, but calls the trigger () method of a single instance to trigger a global event. Similarly, an event processor is attached to a singleton event. For example:
Use Yii; use yii \ base \ Event; use app \ components \ Foo; Yii: $ app-> on ('bar', function ($ event) {echo get_class ($ event-> sender); // Display "app \ components \ Foo"}); Yii: $ app-> trigger ('bar ', new Event (['sender' => new Foo]);
One advantage of global events is that when a processor is appended to an event to be triggered by an object, this object does not need to be generated. Conversely, both processor attaching and event triggering are done through a singleton (such as an application instance.
However, because the namespaces of global events are shared by all parties, we should name global events reasonably, for example, introduce some namespaces (for example, "frontend. mail. sent "," backend. mail. sent ").
Bind an event handler to a component object
$component->attachEventHandler($name, $handler);$component->onBeginRequest = $handler ;
Yii supports binding multiple callback functions to an event. the preceding two methods add a new callback function to an existing event without overwriting the existing callback function.
$ Handler is a PHP callback function. for the form of the callback function, this article will be accompanied by instructions. For example, the init event of the CLogRouter component contains the following code:
Yii::app()->attachEventHandler('onEndRequest',array($this,'processLogs'));
This is to bind the CLogRouter: processLogs () callback function to the onEndRequest of the CApplication object. The CApplication component does have a method named onEndRequest (the onEndRequest event). the code in it activates the corresponding callback function, that is, the CLogRouter: processLogs () method. Therefore, we can conclude from this that the log record actually occurs when the CApplication component exits normally.
When an event needs to be triggered, activate the component event directly, that is, call the event, for example, in the run method of the CApplication component:
if($this->hasEventHandler('onBeginRequest')) $this->onBeginRequest(new CEvent($this));
This triggers the Event Processing function. If the first row is not determined, an exception is thrown in the debugging mode (the YII_DEBUG constant is defined as true, in non-debug mode (the YII_DEBUG constant is defined as false or the YII_DEBUG constant is not defined), no exception is generated.
Callback function format:
General global functions (built-in or user-defined)
call_user_func(‘print', $str);
Class static method, transmitted in array form
call_user_func(array(‘className', ‘print'), $str );
Object method, transmitted as an array
$obj = new className();call_user_func(array($obj, ‘print'), $str );
Anonymous method, similar to anonymous functions in javascript
call_user_func(function($i){echo $i++;},4);
Or use the following form:
$s = function($i) { echo $i++;};call_user_func($s,4);
Summary
The event mechanism of Yii provides a decoupling method. before calling the event, you can call an event as long as you provide the implementation of the event and register it as needed.