Container callbacks回调函数机制

思考并回答以下问题:

  • 在某些操作的节点,比如解析后,插入必要的一些操作。怎么理解?
  • call_user_func ( callable $callback [, mixed $parameter [, mixed $… ]] ) : mixed;
  • app()->rebinding(‘money’, Closure);是这样使用吗?

简介

回调函数在容器中,用的也很多。先说作用,在某些操作的节点,比如解析后,插入必要的一些操作。感觉就像hook和事件Event一样。

在Container中,有好几种callbacks:

1
2
3
4
5
protected $reboundCallbacks = [];              // 所有注册的回调
protected $globalResolvingCallbacks = []; // 所有全局解析回调
protected $globalAfterResolvingCallbacks = []; // 所有全局解析之后回调
protected $resolvingCallbacks = []; // 所有类的解析回调
protected $afterResolvingCallbacks = []; // 所有类的解析之后回调

他们分别出现在不一样的地方被调用。

我们以第一个rebound举例,其他几个大同小异。

实测例子

在extend之前rebinding一个回调函数,当extend完成,会输出this is rebinding callbacks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Money
{
public function getAmount(){
return 100;
}
}

class Dollar extends Money
{
public function getAmount()
{
return 1;
}
}

class ExampleTest extends TestCase
{
public function testClosure()
{
app()->bind('money', Money::class);

app()->rebinding('money', function(){
var_dump("this is rebinding callbacks");
});

app()->extend('money',function(){
return new Dollar();
});

$boss= app()->make('money');
$output = $boss->getAmount();
$this->assertEquals($output, 1);
}
}

源码

触发rebound()回调函数的源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* Fire the "rebound" callbacks for the given abstract type.
*
* @param string $abstract
* @return void
*/
protected function rebound($abstract)
{
$instance = $this->make($abstract);

foreach ($this->getReboundCallbacks($abstract) as $callback) {
call_user_func($callback, $this, $instance);
}
}

1.解析当前的对象。

2.然后查看当前容器中是否存在对应的rebound回调函数,如果有,遍历所有对应的回调函数,使用call_user_func执行回调函数。

2.1 看下getReboundCallbacks,获取对应所有的回调函数,是通过reboundCallbacks数组获得。源码如下:

1
2
3
4
5
6
7
8
9
10
/**
* Get the rebound callbacks for a given type.
*
* @param string $abstract
* @return array
*/
protected function getReboundCallbacks($abstract)
{
return $this->reboundCallbacks[$abstract] ?? [];
}

3.最后这个rebound()方法我们上一章1.2中知道,它会在extend绑定完成后会调用触发。

回调函数的绑定

我们上面涉及了调用,我们下面看下如何绑定。

回调函数的绑定是通过函数rebinding处理的,很简单,就是把对应的回调函数存入reboundCallbacks数组。

最后一句,如果这个对象已经绑定过了,还会贴心的返回这个对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* Bind a new callback to an abstract's rebind event.
*
* @param string $abstract
* @param \Closure $callback
* @return mixed
*/
public function rebinding($abstract, Closure $callback)
{
$this->reboundCallbacks[$abstract = $this->getAlias($abstract)][] = $callback;

if ($this->bound($abstract)) {
return $this->make($abstract);
}
}

总结

回调函数也很简单,我们只要知道在这个例子中,他通过方法rebinding,把回调函数存储在数组reboundCallbacks中,然后使用rebound以及其他几个函数在不同的地方触发。(extend扩展中触发了。)

0%