不知不觉已经发布了7篇关于yii2行为的文章。传送门,今天再分享一篇到掘金专栏。php
为什么使用 yii\base\Component::behaviors() 就能绑定行为,发生了什么?html
咱们先来窥视一下类 Component 内部和绑定行为相关的函数。数组
behaviors() 函数上一篇已经讲了,主要用来绑定行为的,里面接收各类要绑定的行为,它返回了一个数组,虽然咱们如今知道配置这个函数能起到什么效果,可是仍是要研究下,咱们先在yii2的目录下搜索下都哪些函数用了此函数。yii2
只有一句?是的,经过搜索咱们发现只有一个函数调用了它 --- ensureBehaviors()。那就从它开始吧。app
在研究它以前先看看代码yii
//
/** * Makes sure that the behaviors declared in [[behaviors()]] are attached to this component. */
public function ensureBehaviors() {
if ($this->_behaviors === null) {
$this->_behaviors = [];
foreach ($this->behaviors() as $name => $behavior) {
$this->attachBehaviorInternal($name, $behavior);
}
}
}复制代码
逻辑很简单,component组件类用一个属性 _behaviors 来存放它拥有的全部行为对象,若是判断为空,则调用$this->behaviors()函数获取一下,对每一个行为执行 attachBehaviorInternal()函数。函数
看函数名 attachBehaviorInternal() 是绑定行为的意思,那就看一看。this
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;
}复制代码
在第一个if分支内判断 $behavior 是否为 行为类Behavior的一个对象,若是不是则$behavior确定是一些配置,那根据这些配置获得相关行为的对象。spa
总之 $behavior 已是一个行为对象了,咱们先看函数体最后一行,能够知道此函数返回了这个对象。code
接下来咱们来看第二个if分支。
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;
}复制代码
首先说对于 is_int($name) 的判断,还记得咱们在绑定行为的时候么(传送门),在 behaviors() 返回的数组中,咱们能够不为某个行为起名字,那叫作匿名指定,那天然这个key会是一个递增的数字,因此 is_int($name) 在判断是否为匿名行为。
若是是匿名行为,首先 $behavior->attach($this),而后放到 _behaviors 数组中。
若是不是匿名行为,先看看 _behaviors 数组中是否存在,若是存在则先 detach()后 $behavior->attach($this),而后放到 _behaviors 数组中。
这样一圈下来,_behaviors 数组中存放一群行为对象,有些是匿名的,有些是有名字的。对吧。
那么如今咱们已经知道 attachBehaviorInternal函数的第一个功能 --- 填充 _behaviors 数组,反过来回顾 ensureBehaviors的做用,这个ensureBehaviors的一个功能就是确保 _behaviors 数组中有该组件应该有的全部行为对象。
为何是第一个那???由于在 attachBehaviorInternal中咱们发现除了填充数组外,还有一个叫作 $behavior->attach($this);的函数,它也将成为 attachBehaviorInternal / ensureBehaviors 功能之一。
那么 attach() 函数作了什么那?
先看一看它的代码,它在 vendor/yiisoft/yii2/base/Behavior.php 中,被行为对象调用。
public function attach($owner) {
$this->owner = $owner;
foreach ($this->events() as $event => $handler) {
$owner->on($event, is_string($handler) ? [$this, $handler] :
$handler);
}
}复制代码
分析一下,在组件处理本身行为的时候,将$this传递给了行为对象的方法 $behavior->attach($this),而在行为的 attach 方法中 $this->owner = $owner 一下,这意为着什么?
组件的每一个行为对象都有一个属性owner存放了使用他们的组件对象,到此刻组件有 _behaviors 数组存放本身的全部行为对象,而行为有owner属性存放使用了本身的组件对象,它们创建了双向联系。
而关于在attach中的foreach循环体主要是处理事件的,咱们会在行为和事件一篇说明。
此刻,咱们再来概括一下 ensureBehaviors 的功能,也就是绑定方法背后都触发了哪些动做
咱们都知道,绑定行为后,组件对象就能够像使用自身属性和方法同样操做,这彷佛和 ensureBehaviors 没有啥关系,下篇将为你解析当咱们直接调用行为属性的时候,发生了什么?以及在这其中 ensureBehaviors 起到了什么做用?