|
|
@ -5,6 +5,8 @@ |
|
|
|
[Mixin(Mix In可以理解为包含若干个类的部分方法和属性的混合类,英文维基)](http://en.wikipedia.org/wiki/Mixin),允许你增强已有 |
|
|
|
[Mixin(Mix In可以理解为包含若干个类的部分方法和属性的混合类,英文维基)](http://en.wikipedia.org/wiki/Mixin),允许你增强已有 |
|
|
|
[[yii\base\Component|组件]] 类的功能,而无需改变类的继承结构。当一个行为被配属到组件之上是,他会向组件“注入”他的属性与方法,就好像这些方法原本就定义在组件里一样。此外,行为能响应由组件所触发的[事件](basic-events.md),从而自定义或调整组件内默认的代码执行。 |
|
|
|
[[yii\base\Component|组件]] 类的功能,而无需改变类的继承结构。当一个行为被配属到组件之上是,他会向组件“注入”他的属性与方法,就好像这些方法原本就定义在组件里一样。此外,行为能响应由组件所触发的[事件](basic-events.md),从而自定义或调整组件内默认的代码执行。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
> 译者注:mixin直译为‘混入’,trait直译为‘特质’,为避免翻译上的问题,今后我们还是采用英文术语。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
使用行为 <a name="using-behaviors"></a> |
|
|
|
使用行为 <a name="using-behaviors"></a> |
|
|
|
--------------- |
|
|
|
--------------- |
|
|
@ -24,8 +26,8 @@ $component->prop1 = $value; |
|
|
|
与之相似的,你也可以调用行为类的 *public* 方法, |
|
|
|
与之相似的,你也可以调用行为类的 *public* 方法, |
|
|
|
|
|
|
|
|
|
|
|
```php |
|
|
|
```php |
|
|
|
// bar() 是一个定义在行为类中的公共方法 |
|
|
|
// foo() 是一个定义在行为类中的公共方法 |
|
|
|
$component->bar(); |
|
|
|
$component->foo(); |
|
|
|
``` |
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
如你所见,尽管 `$component` 并没有定义 `prop1` 和 `bar()`,它们依旧好像是组件自身定义的一部分一样。 |
|
|
|
如你所见,尽管 `$component` 并没有定义 `prop1` 和 `bar()`,它们依旧好像是组件自身定义的一部分一样。 |
|
|
@ -143,7 +145,7 @@ $component->attachBehaviors([ |
|
|
|
$component->detachBehavior('myBehavior1'); |
|
|
|
$component->detachBehavior('myBehavior1'); |
|
|
|
``` |
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
也可以一次性拆卸掉**所有的**行为: |
|
|
|
也可以一次性拆卸掉**所有**的行为: |
|
|
|
|
|
|
|
|
|
|
|
```php |
|
|
|
```php |
|
|
|
$component->detachBehaviors(); |
|
|
|
$component->detachBehaviors(); |
|
|
@ -153,7 +155,7 @@ $component->detachBehaviors(); |
|
|
|
定义行为 <a name="defining-behaviors"></a> |
|
|
|
定义行为 <a name="defining-behaviors"></a> |
|
|
|
------------------ |
|
|
|
------------------ |
|
|
|
|
|
|
|
|
|
|
|
To define a behavior, create a class by extending from [[yii\base\Behavior]] or its child class. For example, |
|
|
|
要定义一个行为,只需创建新类,继承 [[yii\base\Behavior]] 或其子类。比如, |
|
|
|
|
|
|
|
|
|
|
|
```php |
|
|
|
```php |
|
|
|
namespace app\components; |
|
|
|
namespace app\components; |
|
|
@ -184,15 +186,11 @@ class MyBehavior extends Behavior |
|
|
|
} |
|
|
|
} |
|
|
|
``` |
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
The above code defines the behavior class `app\components\MyBehavior` which will provide two properties |
|
|
|
以上代码定义了行为类 `app\components\MyBehavior` 并为要附加行为的组件提供了两个属性 `prop1` 、 `prop2` 和一个方法 `foo()`。注意,属性 `prop2` 是通过 getter `getProp2()` 和 setter `setProp2()` 定义的。能这样用是因为 [[yii\base\Behavior]] 的祖先类是 [[yii\base\Object]],此祖先类支持用 getter 和 setter 方法定义[属性](concept-properties.md)。 |
|
|
|
`prop1` and `prop2`, and one method `foo()` to the component it is attached to. Note that property `prop2` |
|
|
|
|
|
|
|
is defined via the getter `getProp2()` and the setter `setProp2()`. This is so because [[yii\base\Object]] |
|
|
|
|
|
|
|
is an ancestor class of [[yii\base\Behavior]], which supports defining [properties](concept-properties.md) by getters/setters. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Within a behavior, you can access the component that the behavior is attached to through the [[yii\base\Behavior::owner]] property. |
|
|
|
在行为类之中,你可以通过 [[yii\base\Behavior::owner]] 属性访问行为的组件。 |
|
|
|
|
|
|
|
|
|
|
|
If a behavior needs to respond to the events triggered by the component it is attached to, it should override the |
|
|
|
如果你的行为需要响应其所配属的组件中触发的事件,它需要重写 [[yii\base\Behavior::events()]] 方法。像这样, |
|
|
|
[[yii\base\Behavior::events()]] method. For example, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```php |
|
|
|
```php |
|
|
|
namespace app\components; |
|
|
|
namespace app\components; |
|
|
@ -218,16 +216,13 @@ class MyBehavior extends Behavior |
|
|
|
} |
|
|
|
} |
|
|
|
``` |
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
The [[yii\base\Behavior::events()|events()]] method should return a list of events and their corresponding handlers. |
|
|
|
[[yii\base\Behavior::events()|events()]] 方法需返回一个事件列表和它们相应的处理器。上例声明了 [[yii\db\ActiveRecord::EVENT_BEFORE_VALIDATE|EVENT_BEFORE_VALIDATE]] 事件和它的处理器 `beforeValidate()` 。当指定一个事件处理器时,要使用以下格式之一: |
|
|
|
The above example declares that the [[yii\db\ActiveRecord::EVENT_BEFORE_VALIDATE|EVENT_BEFORE_VALIDATE]] event and |
|
|
|
|
|
|
|
its handler `beforeValidate()`. When specifying an event handler, you may use one of the following formats: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* a string that refers to the name of a method of the behavior class, like the example above; |
|
|
|
* 一条指向行为类的方法名的字符串,如上例所示; |
|
|
|
* an array of an object or class name, and a method name, e.g., `[$object, 'methodName']`; |
|
|
|
* 一个包含对象或类名,以及方法名的数组,如 `[$object, 'methodName']`; |
|
|
|
* an anonymous function. |
|
|
|
* 一个匿名函数 |
|
|
|
|
|
|
|
|
|
|
|
The signature of an event handler should be as follows, where `$event` refers to the event parameter. Please refer |
|
|
|
事件处理器方法的特征格式如下,其中 `$event` 指向事件参数。关于事件的更多细节请参考[事件](concept-events.md)。 |
|
|
|
to the [Events](concept-events.md) section for more details about events. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```php |
|
|
|
```php |
|
|
|
function ($event) { |
|
|
|
function ($event) { |
|
|
@ -238,10 +233,9 @@ function ($event) { |
|
|
|
使用 `TimestampBehavior` <a name="using-timestamp-behavior"></a> |
|
|
|
使用 `TimestampBehavior` <a name="using-timestamp-behavior"></a> |
|
|
|
------------------------- |
|
|
|
------------------------- |
|
|
|
|
|
|
|
|
|
|
|
To wrap up, let's take a look at [[yii\behaviors\TimestampBehavior]] - a behavior that supports automatically |
|
|
|
最后让我们来看看 [[yii\behaviors\TimestampBehavior]] 作为具体实践案例,这个行为支持在 [[yii\db\ActiveRecord|Active Record]] 保存时自动更新它的时间戳类型的 attribute(特性)。 |
|
|
|
updating the timestamp attributes of an [[yii\db\ActiveRecord|Active Record]] when it is being saved. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
First, attach this behavior to the [[yii\db\ActiveRecord|Active Record]] class that you plan to use. |
|
|
|
首先,配属这个行为到目标 [[yii\db\ActiveRecord|Active Record]] 类: |
|
|
|
|
|
|
|
|
|
|
|
```php |
|
|
|
```php |
|
|
|
namespace app\models\User; |
|
|
|
namespace app\models\User; |
|
|
@ -268,14 +262,12 @@ class User extends ActiveRecord |
|
|
|
} |
|
|
|
} |
|
|
|
``` |
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
The behavior configuration above specifies that |
|
|
|
以上行为的配置指定了下面的两条规则: |
|
|
|
|
|
|
|
|
|
|
|
* when the record is being inserted, the behavior should assign the current timestamp to |
|
|
|
* 当记录插入时,行为应该要当前时间戳赋值给 `created_at` 和 `updated_at` 属性; |
|
|
|
the `created_at` and `updated_at` attributes; |
|
|
|
* 当记录更新时,行为应该要当前时间戳赋值给 `updated_at` 属性。 |
|
|
|
* when the record is being updated, the behavior should assign the current timestamp to the `updated_at` attribute. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Now if you have a `User` object and try to save it, you will find its `created_at` and `updated_at` are automatically |
|
|
|
放置上述代码之后,如果有一个 `User` 对象且需要保存,你会发现它的 `created_at` 和 `updated_at` 属性已经自动填充了当前时间戳: |
|
|
|
filled with the current timestamp: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```php |
|
|
|
```php |
|
|
|
$user = new User; |
|
|
|
$user = new User; |
|
|
@ -284,44 +276,35 @@ $user->save(); |
|
|
|
echo $user->created_at; // shows the current timestamp |
|
|
|
echo $user->created_at; // shows the current timestamp |
|
|
|
``` |
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
The [[yii\behaviors\TimestampBehavior|TimestampBehavior]] also offers a useful method |
|
|
|
[[yii\behaviors\TimestampBehavior|TimestampBehavior]] 同时提供一个很好用的名为 [[yii\behaviors\TimestampBehavior::touch()|touch()]] 的方法,该方法会把当前时间戳赋值给指定 attribute 并将其存入数据库: |
|
|
|
[[yii\behaviors\TimestampBehavior::touch()|touch()]] which will assign the current timestamp |
|
|
|
|
|
|
|
to a specified attribute and save it to the database: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```php |
|
|
|
```php |
|
|
|
$user->touch('login_time'); |
|
|
|
$user->touch('login_time'); |
|
|
|
``` |
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
与 Traits(特质)的对比 <a name="comparison-with-traits"></a> |
|
|
|
与 Traits 的对比 <a name="comparison-with-traits"></a> |
|
|
|
---------------------- |
|
|
|
---------------------- |
|
|
|
|
|
|
|
|
|
|
|
While behaviors are similar to [traits](http://www.php.net/traits) in that they both "inject" their |
|
|
|
尽管行为在 "注入" 属性和方法到主类方面类似于 [traits](http://www.php.net/traits) ,它们在很多方面却不相同。如上所述,它们各有利弊。它们更像是互补的而不是相互替代。 |
|
|
|
properties and methods to the primary class, they differ in many aspects. As explained below, they |
|
|
|
|
|
|
|
both have pros and cons. They are more like complements rather than replacements to each other. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Behavior 的好处 <a name="pros-for-behaviors"></a> |
|
|
|
### Behavior 的优势 <a name="pros-for-behaviors"></a> |
|
|
|
|
|
|
|
|
|
|
|
Behavior classes, like normal classes, support inheritance. Traits, on the other hand, |
|
|
|
Behavior 类像普通类支持继承。另一方面,Traits 可以视之为一种 PHP 提供语言级支持的复制粘贴功能,它不支持继承。 |
|
|
|
can be considered as language-supported copy and paste. They do not support inheritance. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Behaviors can be attached and detached to a component dynamically without requiring you to modify the component class. |
|
|
|
Behavior 无须修改组件类就可动态配属到组件或拆除。要使用 trait,就必须修改引用它的类本身。 |
|
|
|
To use a trait, you must modify the class using it. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Behaviors are configurable while traits are not. |
|
|
|
Behavior 是可配置的而 traits 不行。 |
|
|
|
|
|
|
|
|
|
|
|
Behaviors can customize the code execution of a component by responding to its events. |
|
|
|
Behaviors 可以通过响应事件来自定义组件代码的执行。 |
|
|
|
|
|
|
|
|
|
|
|
When there is name conflict among different behaviors attached to the same component, the conflict is |
|
|
|
当不同 Behavior 附加到同一组件产生命名冲突时,这个冲突会以“先附加行为的优先”的方式自动解决。而由不同 traits 引发的命名冲突需要通过手工重命名冲突属性或方法来解决。 |
|
|
|
automatically resolved by respecting the behavior that is attached to the component first. |
|
|
|
|
|
|
|
Name conflict caused by different traits requires you to manually resolve it by renaming the affected |
|
|
|
|
|
|
|
properties or methods. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Traits 的好处 <a name="pros-for-traits"></a> |
|
|
|
### Traits 的优势 <a name="pros-for-traits"></a> |
|
|
|
|
|
|
|
|
|
|
|
Traits are much more efficient than behaviors because behaviors are objects which take both time and memory. |
|
|
|
Trait 比 behaviors 性能好很多很多,因为行为本身就是对象,他需要占用双倍的时间和内存。 |
|
|
|
|
|
|
|
|
|
|
|
IDEs are more friendly to traits as they are language construct. |
|
|
|
作为语言架构的一部分,IDE 对 Trait 更加友好 |
|
|
|
|
|
|
|
|
|
|
|