第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > php behaviors 从behaviors()来研究组件绑定行为的原理

php behaviors 从behaviors()来研究组件绑定行为的原理

时间:2020-03-26 23:46:20

相关推荐

php behaviors 从behaviors()来研究组件绑定行为的原理

不知不觉已经发布了7篇关于yii2行为的文章。传送门,今天再分享一篇到sf专栏。

为何使用 yiibaseComponent::behaviors() 就能绑定行为,发生了什么?

我们先来窥视一下类 Component 内部和绑定行为相关的函数。

yiibaseComponent::behaviors()

yiibaseComponent::ensureBehaviors()

yiibaseComponent::attachBehaviorInternal()

yiibaseBehavior::attach()

behaviors()

behaviors() 函数上一篇已经讲了,主要用来绑定行为的,里面接收各种要绑定的行为,它返回了一个数组,虽然我们现在知道配置这个函数能起到什么效果,但是还是要研究下,我们先在yii2的目录下搜索下都哪些函数用了此函数。

只有一句?是的,通过搜索我们发现只有一个函数调用了它 --- ensureBehaviors()。那就从它开始吧。

ensureBehaviors()

在研究它之前先看看代码

//

/**

* 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()

看函数名 attachBehaviorInternal() 是绑定行为的意思,那就看一看。

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肯定是一些配置,那根据这些配置得到相关行为的对象。

总之 $behavior 已经是一个行为对象了,我们先看函数体最后一行,可以知道此函数返回了这个对象。

接下来我们来看第二个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() 函数做了什么那?

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 的功能,也就是绑定方法背后都触发了哪些动作

我们在组件的子类(比如AR、控制器等)中使用behaviors()来绑定一些行为。

然后有一个叫做 ensureBehaviors 的函数确保了此组件对象和绑定的行为对象可以彼此拥有。

但是

我们都知道,绑定行为后,组件对象就可以像使用自身属性和方法一样操作,这似乎和 ensureBehaviors 没有啥关系,下篇将为你解析当我们直接调用行为属性的时候,发生了什么?以及在这其中 ensureBehaviors 起到了什么作用?

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。