上几篇我们讲解了如何为一个组件类配置行为及其运行原理,本篇为大家讲解yii2组件是如何做到像访问自己属性一样访问行为的属性。
首先要说的是这并不复杂,但是它可以解决你之前的很多疑问,比如为何必须是继承组件(Component)的类才能使用行为。我们都知道在php中有一个魔术方法__get,我们需要先了解一下它。
先解释一下__get方法
当访问不存在或者不能访问的成员变量时对象会自动调用__get()方法.
begin
就是通过这个方法,yii2的Component类访问到了关联行为的属性。
看看文件 vendor/yiisoft/yii2/base/Component.php line127 __get方法。
public function __get($name) {
$getter = 'get' . $name;
if (method_exists($this, $getter)) {
// read property, e.g. getName()
return $this->$getter();
}
// behavior property
$this->ensureBehaviors();
foreach ($this->_behaviors as $behavior) {
if ($behavior->canGetProperty($name)) {
return $behavior->$name;
}
}
...
}
函数首先判断了 method_exists($this, $getter) 是否存在,如果存在则调用,还记得你如何定义AR的关联方法么,就是这段代码实现的。
接下来我们看重头戏,首先 Component 执行了自身的 $this->ensureBehaviors(); 上一篇我们学习了这个函数保证了所有相关行为对象都各就各位,然后函数遍历了所有行为对象。
如果 $behavior->canGetProperty($name) 为真,则返回行为的相关属性(这个属性必须是public的),实现下面的结果
$model = new User();
$model->name;
↓
$model->__get('name');
↓ //$behavior->canGetProperty($name)
return $behavior->name;
就是这样的逻辑。你明白了么?
canGetProperty
接下来说说 canGetProperty 函数,这是object的一个方法,我们知道Component和Behavior都是它的子类,这个方法主要用于判断一个属性是否存在。
因此就是判断在对应行为对象中属性是否存在,就像上面的 $behavior 的 name属性,如果能访问到自然是好,否则这又是一次轮回,调用__get方法看看getName函数是否存在,如果存在也是可以的,比如下面的行为注入到User类
<?php
namespace app\components;
use yii\base\Behavior;
class HelloBehavior extends Behavior {
public function getName(){
return "abei20172";
}
}
// action
$model = new User();
echo $model->name;//abei20172
要注意 canGetProperty 只是判断属性是否存在,并不会检查其范围是否为 public, private, protected。当然最后只有public才能正确访问。
如下代码
namespace app\components;
use yii\base\Behavior;
class HelloBehavior extends Behavior {
protected $name = "abei2017";
}
// action
$model = new User();
echo $model->name;
我们会得到一个异常。
就这样
我们通过__get方法实现了行为属性对组件类的注入,现在你明白为啥能直接访问了吧?下一篇我们说说行为方法的注入原理。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。