建立 Behavior 僅需繼承 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() { /* ... */ }
}
上例定義了兩個屬性(prop1 為公有屬性,prop2 透過 getter/setter 定義)與一個方法 foo()。得益於 yii\base\Object 為祖先類別,支援以存取器定義屬性。Behavior 內部可透過 $this->owner 存取所依附的 Component。
在 Component 子類別中覆寫 behaviors() 回傳配置陣列即可實現靜態綁定:
namespace app\models;
use yii\db\ActiveRecord;
use app\Components\MyBehavior;
class User extends ActiveRecord {
public function behaviors() {
return [
// 匿名行為,僅給類名
MyBehavior::className(),
// 命名行為
'myBehavior2' => MyBehavior::className(),
// 匿名行為,含配置
[
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop3' => 'value3',
],
// 命名行為,含配置
'myBehavior4' => [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop3' => 'value3',
],
];
}
}
亦可於應用配置檔中以 as 關鍵字綁定:
[
'as myBehavior2' => MyBehavior::className(),
'as myBehavior3' => [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop3' => 'value3',
],
]
執行期呼叫 attachBehaviors():
$Component->attachBehaviors([
'myBehavior1' => new MyBehavior, // 命名行為
MyBehavior::className(), // 匿名行為
]);
陣列鍵值為行為名稱(命名行為),無鍵值者為匿名行為。命名行為可透過 getBehavior('name') 取得實例;所有行為可用 getBehaviors() 取得。
綁定涉及四個核心方法:
yii\base\Component::behaviors()yii\base\Component::ensureBehaviors()yii\base\Component::attachBehaviorInternal()yii\base\Behavior::attach()public function ensureBehaviors() {
if ($this->_behaviors === null) {
$this->_behaviors = [];
foreach ($this->behaviors() as $name => $behavior) {
$this->attachBehaviorInternal($name, $behavior);
}
}
}
此方法會在 __get()、__set()、__call()、hasEventHandlers()、on()、off() 等涉及屬性、方法、事件的操作前被呼叫,確保靜態宣告的行為已完成掛載。
private function attachBehaviorInternal($name, $behavior) {
if (!($behavior instanceof Behavior)) {
$behavior = Yii::createObject($behavior); // 支援類名、配置陣列
}
if (is_int($name)) { // 匿名行為
$behavior->attach($this);
$this->_behaviors[] = $behavior;
} else { // 命名行為
if (isset($this->_behaviors[$name])) {
$this->_behaviors[$name]->detach(); // 同名則替換
}
$behavior->attach($this);
$this->_behaviors[$name] = $behavior;
}
return $behavior;
}
public function attach($owner) {
$this->owner = $owner;
foreach ($this->events() as $event => $handler) {
$owner->on($event, is_string($handler) ? [$this, $handler] : $handler);
}
}
做兩件事:設定 $owner 供 Behavior 存取宿主;遍歷 events() 將事件處理器掛載到 Component。
behaviors())、動態(attachBehaviors())、配置檔(as)三種方式。$owner、將 Behavior 宣告的事件處理器掛載至 Component。