Yii源码解读-行为

Yii基础

行为(Behavior)

行为(behavior)能够在不修改现有类的状况下,对类的功能进行扩充。 经过将行为绑定到一个类,可使类具备行为自己所定义的属性和方法,就好像类原本就有这些属性和方法同样。 并且不须要写一个新的类去继承或包含现有类。html

Yii中的行为,是yii\base\Behavior中的实例,只要将Behavior实例绑定到Component实例上便可。可是,Behavior只能与Component类绑定。数组

若是你写了一个类,须要用到行为,那么必需要继承自yii\base\Componentapp

使用行为

Demo:yii

// 定义一个将绑定行为的类
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派生本身的类,以便使用行为。this

  • yii\base\Behavior派生本身的行为类,定义属性和方法。spa

  • 将Component和Behavior绑定起来code

  • 像使用Behavior同样使用Componenthtm

行为的要素

  • $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能支持行为。

参考

  1. http://www.digpage.com/behavior.html

相关文章
相关标签/搜索