行爲(behavior)能夠在不修改現有類的狀況下,對類的功能進行擴充。 經過將行爲綁定到一個類,可使類具備行爲自己所定義的屬性和方法,就好像類原本就有這些屬性和方法同樣。 並且不須要寫一個新的類去繼承或包含現有類。html
Yii中的行爲,是yii\base\Behavior
中的實例,只要將Behavior
實例綁定到Component
實例上便可。可是,Behavior只能與Component類綁定。數組
若是你寫了一個類,須要用到行爲,那麼必需要繼承自yii\base\Component
。app
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()
相比較於使用繼承的方式來擴充類功能,使用行爲的方式,一是沒必要對現有類進行修改,二是PHP不支持多繼承,可是Yii能夠綁定多個行爲,從而達到相似多繼承的效果。
傾向於使用行爲的狀況:
行爲從本質上講,也是PHP的類,所以一個行爲能夠繼承自另外一個行爲,從而實現代碼的複用。而特性只是PHP的一種語法,效果上相似於把特性的代碼導入到了類中從而實現代碼的注入,特性是不支持繼承的。
行爲能夠動態地綁定、解除,而沒必要要對類進行修改。可是特性必須在類在使用 use 語句,要解除特性時,則要刪除這個語句。換句話說,須要對類進行修改。
行爲還以在在配置階段進行綁定,特性就不行了。
行爲能夠用於對事件進行反饋,而特性不行。
當出現命名衝突時,行爲會自行排除衝突,自動使用先綁定的行爲。而特性在發生衝突時,須要人爲干預,修改發生衝突的變量名、屬性名、方法名。
傾向於使用特性的狀況:
特性比行爲在效率上要高一點,由於行爲實際上是類的實例,須要時間和空間進行分配。
特性是PHP的語法,所以,IDE的支持要好一些。目前尚未IDE能支持行爲。
參考