YII2.0框架行为(Behavior)深入详解(10)

从上面的代码中可以看出,Yii还是先是调用了 $this->ensureBehaviors() 确保行为已经绑定。

然后,也是遍历 yii\base\Component::$_behaviros[] 数组。 通过 hasMethod() 方法判断方法是否存在。 如果所绑定的行为中要调用的方法存在,则使用PHP的 call_user_func_array() 调用之。 至于 hasMethod() 方法,我们后面再讲。

注入属性与方法的访问控制

在前面我们针对行为中public和private、protected的成员在所绑定的类中是否可访问举出了具体例子。 这里我们从代码层面解析原因。

在上面的内容,我们知道,一个属性可不可访问,主要看行为的 canGetProperty()canSetProperty() 。 而一个方法可不可调用,主要看行为的 hasMethod() 。 由于 yii\base\Behavior 继承自我们的老朋友 yii\base\Object ,所以上面提到的三个判断方法, 事实上代码都在 Object 中。我们一个一个来看:

public function canGetProperty($name, $checkVars = true)
{
 return method_exists($this, 'get' . $name) || $checkVars &&
  property_exists($this, $name);
}
public function canSetProperty($name, $checkVars = true)
{
 return method_exists($this, 'set' . $name) || $checkVars &&
  property_exists($this, $name);
}
public function hasMethod($name)
{
 return method_exists($this, $name);
}

这三个方法真的谈不上复杂。对此,我们可以得出以下结论:

  • 当向Component绑定的行为读取(写入)一个属性时,如果行为为该属性定义了一个getter (setter),则可以访问。 或者,如果行为确实具有该成员变量即可通过上面的判断,此时,该成员变量可为 public, private, protected。 但最终只有 public 的成员变量才能正确访问。原因在上面讲注入的原理时已经交待了。
  • 当调用Component绑定的行为的一个方法时,如果行为已经定义了该方法,即可通过上面的判断。 此时,这个方法可以为 public, private, protected。 但最终只有 public 的方法才能正确调用。如果你理解了上一款的原因,那么这里也就理解了。

行为与继承和特性(Traits) 的区别

从实现的效果看,你是不是会认为Yii真是多此一举?PHP中要达到这样的效果,可以使用继承呀,可以使用PHP新引入的特性(Traits)呀。但是,行为具有继承和特性所没有的优点,从实际使用的角度讲,继承和特性更靠底层点。靠底层,就意味着开发效率低,运行效率高。行为的引入,是以可以接受的运行效率牺牲为成本,谋取开发效率大提升的一笔买卖。

行为与继承