Yii基础
行为(Behavior)
行为(behavior)可以在不修改现有类的情况下,对类的功能进行扩充。 通过将行为绑定到一个类,可以使类具有行为本身所定义的属性和方法,就好像类本来就有这些属性和方法一样。 而且不需要写一个新的类去继承或包含现有类。
Yii中的行为,是yii\base\Behavior
中的实例,只要将Behavior
实例绑定到Component
实例上即可。但是,Behavior只能与Component类绑定。
如果你写了一个类,需要用到行为,那么必须要继承自yii\base\Component
。
使用行为
Demo:
// 定义一个将绑定行为的类
class MyClass extends yii\base\Component{}
//定义一个行为类,他将绑定到MyClass上
class MyBehavior extends yii\base\Behavior{
public $property1 = 'This is property in MyBehavior.';
public function method1(){
return 'Method in MyBehavior is called.';
}
}
$myClass = new MyClass();
$myBehavior = new MyBehavior();
// Bind
$myClass->attachBehavior('myBehavior', $myBehavior);
// 访问
echo $myClass->property1;
echo $myClass->method1();
使用行为的大致流程:
从
yii\base\Component
派生自己的类,以便使用行为。从
yii\base\Behavior
派生自己的行为类,定义属性和方法。将Component和Behavior绑定起来
像使用Behavior一样使用Component
行为的要素
$owner
:指向行为的依附对象events()
:行为所有要响应的事件attach()
:将行为与Component绑定起来detach()
:你懂的
行为的依附对象
在行为的方法中, $this 引用的是行为本身, 试图通过 $this 来访问行为所依附的Component是行不通的。 正确的方法是通过yii\base\Behavior::$owner
来访问Component。
行为所要响应的事件
重载yii\base\Behavior::events()
方法,表示这个行为将对类何种事件进行何种反馈。
namespace app\Components;
use yii\db\ActiveRecord;
use yii\base\Behavior;
class MyBehavior extends Behavior{
// 重载,使得事件触发时,调用行为中的一些方法
public function events(){
// 在AR的这个事件触发时,调用成员函数beforeValidate
return [ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate']
}
// 行为的成员函数
public function beforeValidate($events){...}
}
行为的绑定和解除
绑定和解除,均需要行为和Component双方共同参与才行。
实际操作,Behavior分别使用attach()
和detach()
来实现即可。
定义一个行为
定义一个行为,即是准备好注入到现有类的属性和方法。即要写一个Behavior
的子类
namespace app\Components;
use yii\base\Behavior;
class MyBehavior extends Behavior{
public $prop1;
private $_prop2;
private $_prop3;
private $_prop4;
public function getProp2(){
return $this->prop2;
}
public function setProp3($value){
$this->_prop3 = $value;
}
public function foo(){}
protected function bar(){}
}
该子类继承了Behavior
,同时间接的继承了Object
。当该类与Component绑定后,Component也就拥有了相对应public的属性和方法,而private和protected的属性和方法并不能得到。
行为的绑定
有两种方法可以将一个Behavior
绑定到一个yii\base\Component
上。
静态方法:在代码没有跑起来之前
静态绑定,只需要重载yii\base\Component::bahaviors()
就可以了。该方法描述类所具有的行为。描述方法:
配置来描述
Behavior类名
Behavior类的配置数组
namespace app\models;
use yii\db\ActiveRecord;
use app\Components\MyBehavior;
class User extends ActiveRecord{
public function behaviors(){
return [
// 匿名行为
MyBehavior::className(),
// 名为myBehavior2的行为
'myBehavior2' => MyBehavior::className(),
// 匿名行为 + 给出配置数组
[
'class' => MyBehavior::className(),
'prop1' => 'v1',
'prop3' => 'v3',
],
// 带名称的行为 + 配置数组
'myBehavior4' => [
'class' => MyBehavior::className(),
'prop1' => 'v1',
'prop3' => 'v3'
]
];
}
}
另外通过配置文件:
[
'as myBehavior2' => MyBehavior::className(),
]
动态方法绑定行为
需要调用yii\base\Component::attachBehaviors()
$Component->attachBehaviors([
'myBehavior1' => new MyBehavior,
]);
$behavior = $Component->getBehavior('myBehavior1');
绑定的内部原理
yii\base\Component::behaviors()
yii\base\Component::ensureBehaviors()
yii\base\Component::attachBehaviorInternal()
yii\base\Behavior::attach()
关于绑定,做个小结:
绑定的动作从Component发起;
静态绑定通过重载 yii\base\Componet::behaviors() 实现;
动态绑定通过调用 yii\base\Component::attachBehaviors() 实现;
行为还可以通过为 Component 配置 as 配置项进行绑定;
行为有匿名行为和命名行为之分,区别在于绑定时是否给出命名。 命名行为可以通过其命名进行标识,从而有针对性地进行解除等操作;
绑定过程中,后绑定的行为会取代已经绑定的同名行为;
绑定的意义有两点,一是为行为设置 $owner 。二是将行为中拟响应的事件的handler绑定到类中去。
行为响应的事件实例
绑定和解除的过程,实际上就是将行为中的事件handler
绑定到类中去。行为用的最多的,也是对于Component各种事件的响应。
行为的属性和方法注入原理
__get()
, __set()
, __call()
行为与继承和特性(Traits)的区别
相比较于使用继承的方式来扩充类功能,使用行为的方式,一是不必对现有类进行修改,二是PHP不支持多继承,但是Yii可以绑定多个行为,从而达到类似多继承的效果。
倾向于使用行为的情况:
行为从本质上讲,也是PHP的类,因此一个行为可以继承自另一个行为,从而实现代码的复用。而特性只是PHP的一种语法,效果上类似于把特性的代码导入到了类中从而实现代码的注入,特性是不支持继承的。
行为可以动态地绑定、解除,而不必要对类进行修改。但是特性必须在类在使用 use 语句,要解除特性时,则要删除这个语句。换句话说,需要对类进行修改。
行为还以在在配置阶段进行绑定,特性就不行了。
行为可以用于对事件进行反馈,而特性不行。
当出现命名冲突时,行为会自行排除冲突,自动使用先绑定的行为。而特性在发生冲突时,需要人为干预,修改发生冲突的变量名、属性名、方法名。
倾向于使用特性的情况:
特性比行为在效率上要高一点,因为行为其实是类的实例,需要时间和空间进行分配。
特性是PHP的语法,因此,IDE的支持要好一些。目前还没有IDE能支持行为。
参考
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。