1.9 - Laravel - 5.6 - tag 解析机制
先说作用,给某一类的绑定分配一个标记来表示他们是一类的,可以通过这个标记取出同一类下面的所有的绑定。
看看怎么用就知道了:
//定义两个实体类, 都标记名字为currency
//然后使用tagged取出currency就是可以取出abstruct的实体对象。
public function testTags()
{
$this->app->tag(Rmb::class, 'currency');
$this->app->tag(Dollar::class, 'currency');
$currencyArray = $this->app->tagged('currency');
$this->assertTrue($currencyArray[0] instanceof Rmb);
$this->assertTrue($currencyArray[1] instanceof Dollar);
}
注意这里:我们绑定的时候还是一个abstruct,就是说容器中还没有对象,但是我们tagged取出的时候都变成对象了。因为make可以直接解析类路径,而tagged使用了make方法,我们看下面源代码。
1.tag 方法源代码
1.0 还是先说参数,传入的$abstracts可以是类路径,也可以是一个绑定的别名或者字符串。如果是后者,需要事先使用bind方法绑定对应的concrete。如果是类路径则可以直接使用,参见前面make方法。
源代码:
public function tag($abstracts, $tags)
{
$tags = is_array($tags) ? $tags : array_slice(func_get_args(), 1);
foreach ($tags as $tag) {
if (! isset($this->tags[$tag])) {
$this->tags[$tag] = [];
}
foreach ((array) $abstracts as $abstract) {
$this->tags[$tag][] = $abstract;
}
}
}
1.1 判断第二个参数$tags是不是一个数组,如果不是数组,他可以是一个参数。
这里可以看到,这里也可以传入多个参数。array_slice会吧第二个参数,以及后面所有的参数都转换成一个数组返回。
$tags = is_array($tags) ? $tags : array_slice(func_get_args(), 1);
什么意思呢,举例:
//可以这样
$this->app->tag(Rmb::class, 'currency');
//也可以传入数组
$this->app->tag(Rmb::class, ['currency', 'money']);
//也可以这样
$this->app->tag(Rmb::class, 'currency',‘money’);
最后一种,我们看源码就知道可以这样使用,虽然我感觉可能不是一个好的写法。
1.2 下面就简单了,主要分两步:
a.遍历这个tags数组,如果在tags数组(protected $tags = [];)
中不存在这个tag那么创建一个空的子数组。
b.遍历前面的第一个参数$abstracts
,他会强行转换成一个数组,说明$abstruct可以是一个字符串,也可以是一个数组。把当前的abstruct对应的值存储到上面我们创建的子数组tag中。
这里我们同时知道了tags数组
作用以及存储格式。
foreach ($tags as $tag) {
if (! isset($this->tags[$tag])) {
$this->tags[$tag] = [];
}
foreach ((array) $abstracts as $abstract) {
$this->tags[$tag][] = $abstract;
}
}
这是tags的存储过程。
2.tagged方法源代码,看看以tag标记的一类绑定如何获取
public function tagged($tag)
{
$results = [];
if (isset($this->tags[$tag])) {
foreach ($this->tags[$tag] as $abstract) {
$results[] = $this->make($abstract);
}
}
return $results;
}
2.1 其实很简单,也是两个逻辑:
a.先判断当前容器的 tags 数组中有没有对应的值,如果没有直接返回空数组
b.如果有,遍历这个子tag数组,分别使用make函数解析这个$abstruct
这里我们就能明白,为什么我们可以不用事先绑定类路径,而直接使用就能绑定成功,因为我们知道make解析的时候,如果在binding数组中找不到对应的值,他会使用build函数直接解析。
但是我们,也看到,这个make解析的时候是没有第二个参数parameters的,说明什么呢,如果这个类路径有自定义的依赖并且这个依赖没有默认值,它是无法实例化的。因为make他需要我们传入第二个参数才能实例化
实例测试:
- 测试提供类:
class AusDollars{ private $amount; public function __construct($amount) { $this->amount = $amount; } }
class Rmb{}
class Dollar
{
public function __construct()
{
}
public function getAmount()
{
return 1;
}
}
Class Currency
{
private $dollar;
public function __construct(Dollar $dollar)
{
$this->dollar = $dollar;
}
public function getAmount()
{
return $this->dollar->getAmount();
}
}
1.测试多个参数情况,以及直接使用类路径
public function testTags()
{
$this->app->bind(‘rmb’, Rmb::class);
//多个参数
$this->app->tag('rmb', 'currency', 'money');
//直接使用类路径
$this->app->tag(Dollar::class, 'currency', 'money');
$currencyArray = $this->app->tagged('money');
$this->assertTrue($currencyArray[0] instanceof Rmb);
$this->assertTrue($currencyArray[1] instanceof Dollar);
}
2.测试使用tag直接绑定有依赖的类路径,会报错
public function testTagsWithDependency()
{
$this->app->tag(AusDollars::class, ‘currency’, ‘money’);
try{
$this->app->tagged(‘money’);
}catch(\Exception $e){
$this->assertContains(“Unresolvable dependency resolving”,$e->getMessage());
}
}
会报这样的错
`Unresolvable dependency resolving [Parameter #0 [ <required> $amount ]] in class ...`
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: