yii 组件
Welcome once again to this tour of the Yii Framework’s CComponent
class. This three-part series demonstrates how Yii uses a component-based architecture and how the class implements properties, configuration, events, and behaviors. In Part 1 you saw how Yii uses PHP’s magic methods to implement component properties. In this article, which is Part 2 of the series, I’ll show you how you can do event-based programming in PHP. I’ll also show you how the component class makes it possible.
再次欢迎您访问Yii Framework的CComponent
类。 这个由三部分组成的系列演示Yii如何使用基于组件的体系结构以及该类如何实现属性,配置,事件和行为。 在第1部分中,您了解了Yii如何使用PHP的魔术方法来实现组件属性。 在本系列文章的第2部分中,我将向您展示如何在PHP中进行基于事件的编程。 我还将向您展示组件类如何使其成为可能。
大事记 (Events)
An application event is something that occurs which might be of interest to other bits of code. A standard event in most GUI applications would be a “click” event, but the sky’s the limit and what events you define is really up to you. For example, when a user registers you’ll often want to send her an email welcoming her to your application. You could define “Registration complete” as an event. Rather than hard-coding email logic or even setting different user properties in your code, the module could simply raise an event and forget about any specific implementation details. The details can be provided by application-specific modules allowing you to keep individual requirements separate from your reusable code. Events allow you to attach a potentially unlimited amount of functionality without changing your core modules and components.
应用程序事件是发生的事情,它可能与其他代码位有关。 在大多数GUI应用程序中,标准事件将是“单击”事件,但是天空是极限,您定义的事件实际上取决于您。 例如,当用户注册时,您通常会向她发送一封电子邮件,欢迎她使用您的应用程序。 您可以将“注册完成”定义为事件。 该模块无需硬编码电子邮件逻辑或在代码中设置不同的用户属性,而只需引发一个事件而忽略任何特定的实现细节。 可以通过特定于应用程序的模块来提供详细信息,从而使您可以将各个需求与可重用的代码分开。 通过事件,您可以附加无限量的功能,而无需更改核心模块和组件。
There are generally three steps to implementing an event:
实施事件通常需要三个步骤:
- Define the event 定义事件
- Attach custom functionality to the event 将自定义功能附加到事件
- Trigger the event when it happens 事件发生时触发事件
定义事件
首先,您需要定义允许Yii为其附加功能的事件。 继续执行用户注册示例,您将创建一个任意事件onUserRegistered
,该事件在用户成功注册后引发。 这将在您的用户模块代码中定义。 (Defining Events
First you need to define the event allowing Yii to attach functions to it. Continuing with the user registration example, you would create a new event arbitrarily called onUserRegistered
that is raised after a user has been successfully registered. This would be defined within my your user module’s code.)
<?php
public function onUserRegistered($event) {
$this->raiseEvent("onUserRegistered", $event);
}
Events in Yii are defined by simply adding a function with “on” prefixed to the method name. In order to attach a function to an object you need to be able to access the object from other areas of the application. The event is added to the user component so that it can be accessed throughout the application through Yii::app()->user
.
Yii中的事件是通过简单地在方法名称前添加带有“ on”前缀的函数来定义的。 为了将功能附加到对象,您需要能够从应用程序的其他区域访问该对象。 该事件已添加到用户组件,以便可以通过Yii::app()->user
在整个应用程序中对其进行访问。
触发事件 (Triggering Events)
The controller class of the user module would be responsible for triggering the event when it actually occurs.
当事件实际发生时,用户模块的控制器类将负责触发该事件。
<?php
public function actionUserRegister() {
// code to register a user and add to the database
// ...
// user has been successfully registered so lets raise an event to tell the world
$e = new CEvent($this, array("user" => $user));
Yii::app()->user->onUserRegistered($e);
}
Once a user has been successfully registered and added to your database, you’ll want to tell the world. This code raises the event. Events do not know the specific details of the function they are calling so all handling functions must have the same interface. In Yii, all handling functions expect one parameter which is a CEvent
object. The CEvent
object expects two parameters: a reference to the object that raised the event, and an optional array of parameters that can be used to store specific information relating to the particular event (these parameters can be accessed later by your handling functions). In this example I want all handling functions to be able to access the user object that was just registered. To do this I pass an array of array("user" => $user)
where $user
is an object representing our recently registered user. I then trigger the event and evoke Yii’s raiseEvent()
function by calling the function onUserRegistered()
and pass in the event object.
成功注册用户并将其添加到您的数据库后,您需要向世界展示。 此代码引发事件。 事件不知道它们正在调用的函数的详细信息,因此所有处理函数必须具有相同的接口。 在Yii中,所有处理函数都期望一个参数,该参数是CEvent
对象。 CEvent
对象需要两个参数:对引发事件的对象的引用,以及可用于存储与特定事件有关的特定信息的可选参数数组(这些参数以后可以由您的处理函数访问)。 在此示例中,我希望所有处理功能都能够访问刚刚注册的用户对象。 为此,我传递了一个数组array("user" => $user)
,其中$user
是代表我们最近注册的用户的对象。 然后,我通过调用onUserRegistered()
函数并触发事件对象来触发事件并调用Yii的raiseEvent()
函数。
That is all the code that needs to be added to the user module. Now any additional code anywhere in your application can attach additional functionality to be executed when a new user registers.
那就是所有需要添加到用户模块中的代码。 现在,应用程序中任何位置的任何其他代码都可以附加新用户注册时要执行的其他功能。
附加活动 (Attaching Events)
Continuing with the example, let’s see how attach an event’s callback.
继续该示例,让我们看看如何附加事件的回调。
<?php
public function init() {
Yii::app()->user->onUserRegistered = array($this, "sendMyEmail");
}
public function sendMyEmail($event) {
$user = $event->params["user"];
mail($user->email, "Welcome to this amazing event app", "Hello...");
}
I’ve attaching the sendMyEmail()
method to the onUserRegistered
event so now when a new user registers the sendMyEmail()
function will be called. Alternatively, in PHP 5.3 or greater you can specify an anonymous function. Yii supports assigning any value to an event that would also return true if passed into the PHP is_callable()
function.
我已经将sendMyEmail()
方法附加到onUserRegistered
事件,所以现在当新用户注册sendMyEmail()
函数时,将对其进行调用。 另外,在PHP 5.3或更高版本中,您可以指定一个匿名函数。 Yii支持为事件分配任何值,如果传递给PHP is_callable()
函数,该事件也将返回true。
Yii的魔术 (Yii’s Magic)
Now let’s look at how Yii implements events; managing events is all handled by cleverness in the CComponent
class. In order to implement events the component class has to implement the three main concepts:
现在让我们看一下Yii如何实现事件; 管理事件全部由CComponent
类中的CComponent
处理。 为了实现事件,组件类必须实现三个主要概念:
- Defining events – Yii need to store or be able to lookup defined events. 定义事件– Yii需要存储或能够查找定义的事件。
- Triggering events – When an event occurs, Yii need to call all of our PHP functions attached to the event. 触发事件–发生事件时,Yii需要调用该事件附带的所有PHP函数。
- Attaching events – Yii need a mechanism to store a list of valid PHP callbacks against an event. 附加事件– Yii需要一种机制来存储针对事件的有效PHP回调列表。
The mechanism for defining events in Yii is to simply create a function with the “on” prefix as you saw earlier. The mechanism for triggering an event is to add $this->raiseEvent("onMethodName");
within the defined event and simply call the method when the event occurs in your code. This leaves us with two implementation details left:
在Yii中定义事件的机制是简单地创建一个带有“ on”前缀的函数,如前所述。 触发事件的机制是添加$this->raiseEvent("onMethodName");
在已定义的事件中,只需在事件在代码中发生时调用该方法即可。 剩下两个实现细节:
- Attaching functions to the event. 将功能附加到事件。
- Calling all functions attached to the event when it is triggered. 触发事件时,调用附加到事件的所有函数。
To attach the event you use the code onMyEventName = callback
, which means the implementation for attaching functions to events must be handled in the components magic __set
method.
要附加事件,请使用代码onMyEventName = callback
,这意味着必须在组件魔术__set
方法中处理将函数附加到事件的实现。
<?php
public function __set($name, $value){
if (strncasecmp($name, "on", 2) === 0 && method_exists($this, $name)) {
$name = strtolower($name);
if (!isset($this->_e[$name])) {
$this->_e[$name] = new CList();
}
return $this->_e[$name]->add($value);
}
}
The implementation first checks if the value of $name
starts with the text “on” and that a method also exists with the same name as the value. If it does, Yii assumes $value
is a representation of a callback which it needs to attach to the event defined by $name
. Yii has a private member variable $_e
which holds an array of callbacks keyed by event names, and it simply adds the callback to the list for the particular event key.
该实现首先检查$name
的值是否以文本“ on”开头,并且是否存在与该名称同名的方法。 如果是这样,Yii假设$value
是回调的表示形式,它需要附加到$name
定义的事件上。 Yii有一个私有成员变量$_e
,该变量包含一个由事件名称作为键的回调数组,它只是将回调添加到特定事件键的列表中。
$_e => array(
'onUserRegistered' => array(
0 => array(object, 'sendMyEmail')
),
'onSomeOtherEvent'=>array(
0 => function(){}
1 => ...
)
)
All that’s left now is to call the attached functions when the event is triggered. From looking at the array of stored events, this could be as easy as looking up the event in the $_e
variable, and iterating through each callback in the array and running it.
现在剩下的就是在事件触发时调用附加的函数。 通过查看存储的事件数组,这就像在$_e
变量中查找事件,然后遍历数组中的每个回调并运行它一样容易。
public function raiseEvent($name, $event) {
foreach ($this->_e[$name] as $handler) {
if (is_array($handler)) {
// an array: 0 - object, 1 - method name
list($object, $method) = $handler;
$object->$method($event);
}
else {
// PHP 5.3+ anonymous function
call_user_func($handler, $event);
}
}
}
I’ve refactored the raiseEvent()
method so it’s easier to read for our demo, but the Yii implementation has more error checking and handles additional more callback types, such as static methods.
我已经重构了raiseEvent()
方法,因此对于我们的演示来说,它更易于阅读,但是Yii实现具有更多的错误检查功能,并且可以处理更多的回调类型,例如静态方法。
摘要 (Summary)
Events are a great concept to implement for robust, flexible code. In this article you’ve learned how to create reusable components that can have their functionality extended through the use of events, and have seen seen how the Yii framework’s CComponent
class implements and manages events in PHP. Of course, the usage and implementation details may be specific to Yii but the concept itself is universal.
事件是实现健壮,灵活的代码的绝佳概念。 在本文中,您学习了如何创建可重用的组件,这些组件可通过事件的使用扩展其功能,并了解了Yii框架的CComponent
类如何在PHP中实现和管理事件。 当然,用法和实现细节可能特定于Yii,但是概念本身是通用的。
This wraps up our second article in this three part series. The final article walks through creating and implementing behaviors, another great way to extend a component’s functionality while keeping it easy to reuse.
这总结了这三部分系列的第二篇文章。 最后一篇文章介绍了行为的创建和实现,这是扩展组件功能同时又易于重用的另一种好方法。
Image via Filipchuk Oleg Vasiliovich / Shutterstock
图片来自Filipchuk Oleg Vasiliovich / Shutterstock
yii 组件