行为是 yii\base\Behavior 或其子类的实例。行为,也称为 mixin,允许您增强现有 组件 类的功能,而无需更改类的继承关系。将行为附加到组件会将行为的方法和属性“注入”到组件中,使这些方法和属性可访问,就像它们在组件类本身中定义一样。此外,行为可以响应组件触发的 事件,这使得行为还可以自定义组件的正常代码执行。
要定义行为,请创建一个扩展 yii\base\Behavior 或其子类的类。例如
namespace app\components;
use yii\base\Behavior;
class MyBehavior extends Behavior
{
public $prop1;
private $_prop2;
public function getProp2()
{
return $this->_prop2;
}
public function setProp2($value)
{
$this->_prop2 = $value;
}
public function foo()
{
// ...
}
}
以上代码定义了行为类 app\components\MyBehavior
,它有两个属性 prop1
和 prop2
以及一个方法 foo()
。请注意,属性 prop2
是通过 getter getProp2()
和 setter setProp2()
定义的。这是因为 yii\base\Behavior 扩展了 yii\base\BaseObject,因此支持通过 getter 和 setter 定义 属性。
因为此类是一个行为,所以当它附加到组件时,该组件也将具有 prop1
和 prop2
属性以及 foo()
方法。
提示:在行为内部,您可以通过 yii\base\Behavior::$owner 属性访问附加行为的组件。
注意:如果覆盖了行为的 yii\base\Behavior::__get() 和/或 yii\base\Behavior::__set() 方法,则还需要覆盖 yii\base\Behavior::canGetProperty() 和/或 yii\base\Behavior::canSetProperty()。
如果某个行为需要响应其所附加组件触发的事件,则应重写 yii\base\Behavior::events() 方法。例如
namespace app\components;
use yii\db\ActiveRecord;
use yii\base\Behavior;
class MyBehavior extends Behavior
{
// ...
public function events()
{
return [
ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate',
];
}
public function beforeValidate($event)
{
// ...
}
}
该 events() 方法应返回事件列表及其对应的处理程序。以上示例声明了 EVENT_BEFORE_VALIDATE 事件存在,并定义了其处理程序 beforeValidate()
。在指定事件处理程序时,可以使用以下格式之一:
[$object, 'methodName']
;事件处理程序的签名应如下所示,其中 $event
指的是事件参数。有关事件的更多详细信息,请参阅 事件 部分。
function ($event) {
}
您可以静态或动态地将行为附加到 组件。前者在实践中更为常见。
要静态地附加行为,请重写要附加行为的组件类的 behaviors() 方法。该 behaviors() 方法应返回行为 配置 列表。每个行为配置可以是行为类名或配置数组。
namespace app\models;
use yii\db\ActiveRecord;
use app\components\MyBehavior;
class User extends ActiveRecord
{
public function behaviors()
{
return [
// anonymous behavior, behavior class name only
MyBehavior::class,
// named behavior, behavior class name only
'myBehavior2' => MyBehavior::class,
// anonymous behavior, configuration array
[
'class' => MyBehavior::class,
'prop1' => 'value1',
'prop2' => 'value2',
],
// named behavior, configuration array
'myBehavior4' => [
'class' => MyBehavior::class,
'prop1' => 'value1',
'prop2' => 'value2',
]
];
}
}
您可以通过指定与行为配置对应的数组键来将名称与行为关联。在这种情况下,该行为被称为命名行为。在上面的示例中,有两个命名行为:myBehavior2
和 myBehavior4
。如果某个行为没有与名称关联,则称为匿名行为。
要动态地附加行为,请调用要附加行为的组件的 yii\base\Component::attachBehavior() 方法。
use app\components\MyBehavior;
// attach a behavior object
$component->attachBehavior('myBehavior1', new MyBehavior());
// attach a behavior class
$component->attachBehavior('myBehavior2', MyBehavior::class);
// attach a configuration array
$component->attachBehavior('myBehavior3', [
'class' => MyBehavior::class,
'prop1' => 'value1',
'prop2' => 'value2',
]);
您可以使用 yii\base\Component::attachBehaviors() 方法一次附加多个行为。
$component->attachBehaviors([
'myBehavior1' => new MyBehavior(), // a named behavior
MyBehavior::class, // an anonymous behavior
]);
您还可以通过 配置 附加行为,如下所示:
[
'as myBehavior2' => MyBehavior::class,
'as myBehavior3' => [
'class' => MyBehavior::class,
'prop1' => 'value1',
'prop2' => 'value2',
],
]
有关更多详细信息,请参阅 配置 部分。
要使用某个行为,首先请按照上述说明将其附加到 组件。一旦某个行为附加到组件,其用法就非常简单了。
您可以通过其所附加的组件访问行为定义的公共成员变量或 属性(通过 getter 和/或 setter)。
// "prop1" is a property defined in the behavior class
echo $component->prop1;
$component->prop1 = $value;
您也可以类似地调用行为的公共方法。
// foo() is a public method defined in the behavior class
$component->foo();
如您所见,尽管 $component
没有定义 prop1
和 foo()
,但由于附加了行为,因此可以使用它们,就像它们是组件定义的一部分一样。
如果两个行为定义了相同的属性或方法,并且它们都附加到同一个组件,则当访问该属性或方法时,首先附加到组件的行为将优先。
行为在附加到组件时可能会与名称关联。如果是这种情况,您可以使用该名称访问行为对象。
$behavior = $component->getBehavior('myBehavior');
您还可以获取附加到组件的所有行为。
$behaviors = $component->getBehaviors();
要分离行为,请使用与行为关联的名称调用 yii\base\Component::detachBehavior()。
$component->detachBehavior('myBehavior1');
您还可以分离所有行为。
$component->detachBehaviors();
TimestampBehavior
¶最后,让我们看看 yii\behaviors\TimestampBehavior。此行为支持在每次通过 insert()
、update()
或 save()
方法保存模型时自动更新 Active Record 模型的时间戳属性。
首先,将此行为附加到您计划使用的 Active Record 类。
namespace app\models\User;
use yii\db\ActiveRecord;
use yii\behaviors\TimestampBehavior;
class User extends ActiveRecord
{
// ...
public function behaviors()
{
return [
[
'class' => TimestampBehavior::class,
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
],
// if you're using datetime instead of UNIX timestamp:
// 'value' => new Expression('NOW()'),
],
];
}
}
上面的行为配置指定,当记录被
created_at
和 updated_at
属性。updated_at
属性。注意: 为了使上述实现与 MySQL 数据库一起使用,请将列(
created_at
、updated_at
)声明为 int(11),以便存储 UNIX 时间戳。
有了这段代码,如果您有一个 User
对象并尝试保存它,您会发现它的 created_at
和 updated_at
会自动填充当前的 UNIX 时间戳。
$user = new User;
$user->email = '[email protected]';
$user->save();
echo $user->created_at; // shows the current timestamp
该 TimestampBehavior 还提供了一个有用的方法 touch(),它会将当前时间戳分配给指定的属性并将其保存到数据库中。
$user->touch('login_time');
有几个内置和外部行为可用。
虽然行为类似于 特性,因为它们都“注入”其属性和方法到主类中,但它们在许多方面都不同。如下所述,它们各有优缺点。它们更像是彼此的补充,而不是替代品。
行为类,就像普通类一样,支持继承。另一方面,特性可以被认为是语言支持的复制粘贴。它们不支持继承。
行为可以动态地附加和分离到组件,而无需修改组件类。要使用特性,您必须修改使用它的类的代码。
行为是可配置的,而特性则不是。
行为可以通过响应组件的事件来自定义组件的代码执行。
当附加到同一组件的不同行为之间存在名称冲突时,冲突会通过优先考虑首先附加到组件的行为来自动解决。由不同特性引起的名称冲突需要通过重命名受影响的属性或方法来手动解决。
特性比行为效率高得多,因为行为是既占用时间又占用内存的对象。
IDE 对特性更友好,因为它们是本机语言构造。
发现错别字或您认为此页面需要改进?
在 github 上编辑它 !
要运行默认操作,请声明 init() 函数如下所示:
请 注册 或 登录 以发表评论。