先說作用,給某一類的繫結分配一個標記來表示他們是一類的,可以通過這個標記取出同一類下面的所有的繫結。
看看怎麼用就知道了:
//定義兩個實體類, 都標記名字為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 協議》,轉載必須註明作者和本文連結