核心提示:Yii2理解Component。继承与实现 event和behaviors behaviors 添加Behavior到Component ensureBehaviors attachBehavior和...
Yii2理解Component。继承与实现 event和behaviors behaviors 添加Behavior到Component ensureBehaviors attachBehavior和attachBehaviors detachBehavior和detachBehaviors __get __set on和off
1 继承与实现
Component继承与Object, Object实现了Configurable接口, 该接口要求在函数参数列表末尾加上 $config
public function __construct($config = []) { if (!empty($config)) { Yii::configure($this, $config); } $this->init(); }
2 event和behaviors
private $_events = []; private $_behaviors;
该类的重点就是事件(class Event)和行为(class Behavior)
3 behaviors()
public function behaviors() { return []; }
Component的派生类如果有需要使用到Behavior, 就需要重载这个函数。
比如Controller设置规则。
4 添加Behavior到Component
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; }
5 ensureBehaviors
Component将会在很多地方调用该函数, 确保行为被添加到该组件中
public function ensureBehaviors() { if ($this->_behaviors === null) { $this->_behaviors = []; foreach ($this->behaviors() as $name => $behavior) { $this->attachBehaviorInternal($name, $behavior); } } }
假设XXController::behaviors()定义如下:
use yii\filters\AccessControl; use yii\filters\VerbFilter; public function behaviors() { return [ // 指定了行为名称 'access' => [ 'class' => AccessControl::className(), 'rules' => [ [ 'actions' => ['login', 'error', 'register'], 'allow' => true, ], [ 'allow' => true, 'roles' => ['@'], ] ] ], // 未指定行为名称 [ 'class' => VerbFilter::className(), 'actions' => [ 'logout' => ['post'], 'delete' => ['post'], 'upload'=>['post'], ] ] ]; }
一个是命名为access的行为, 一个是匿名行为。
将其打印输出:
array(2) { // --------------------- access行为 ["access"]=> array(2) { ["class"]=> string(25) "yii\filters\AccessControl" ["rules"]=> array(2) { [0]=> array(2) { ["actions"]=> array(3) { [0]=> string(5) "login" [1]=> string(5) "error" [2]=> string(8) "register" } ["allow"]=> bool(true) } [1]=> array(2) { ["allow"]=> bool(true) ["roles"]=> array(1) { [0]=> string(1) "@" } } } } // --------------------- 数字表示匿名行为 [0]=> array(2) { ["class"]=> string(22) "yii\filters\VerbFilter" ["actions"]=> array(3) { ["logout"]=> array(1) { [0]=> string(4) "post" } ["delete"]=> array(1) { [0]=> string(4) "post" } ["upload"]=> array(1) { [0]=> string(4) "post" } } } }
两个行为会通过attachBehaviorInternal添加到Component中
6 attachBehavior和attachBehaviors
这两个函数用于额外再添加行为
7 detachBehavior和detachBehaviors
这两个函数用于移除行为
8 __get
Component重写了__get函数, 这里就是将Behavior中的属性绑定到Component的地方
public function __get($name) { $getter = 'get' . $name; // 如果能在Component中找到该属性, 则返回该属性的值 if (method_exists($this, $getter)) { return $this->$getter(); } else { // 确保行为都绑定了 $this->ensureBehaviors(); // 如果能在各个Behavior中找到该属性,则调用Behavior中的值 foreach ($this->_behaviors as $behavior) { if ($behavior->canGetProperty($name)) { return $behavior->$name; } } } ... }
9 __set
Component重写了__set函数
public function __set($name, $value) { $setter = 'set' . $name; if (method_exists($this, $setter)) { $this->$setter($value); return; } // 如果以'on '开头则认为是添加事件 elseif (strncmp($name, 'on ', 3) === 0) { // 截取第3个元素之后的字符串, 做为事件名称 $this->on(trim(substr($name, 3)), $value); return; } // 如果以'as '开头则认为是添加行为 elseif (strncmp($name, 'as ', 3) === 0) { // 截取第3个元素之后的字符串, 做为行为名称 $name = trim(substr($name, 3)); $this->attachBehavior($name, $value instanceof Behavior ? $value : Yii::createObject($value)); return; } else { // behavior property $this->ensureBehaviors(); foreach ($this->_behaviors as $behavior) { if ($behavior->canSetProperty($name)) { $behavior->$name = $value; return; } } } ... }
10 on和off
on 和 off分别是添加事件和移除事件