架構 —— 服務容器

在一個服務提供者中,能夠經過$this->app變量訪問容器,而後使用bind方法註冊一個綁定,該方法須要兩個參數,第一個參數是咱們想要註冊的類名或接口名稱,第二個參數是返回類的實例的閉包:php

$this->app->bind('HelpSpot\API', function ($app) {    return new HelpSpot\API($app['HttpClient']);
});

注意到咱們接受容器自己做爲解析器的一個參數,而後咱們可使用該容器來解析咱們正在構建的對象的子依賴。html

綁定一個單例laravel

singleton方法綁定一個只須要解析一次的類或接口到容器,而後接下來對容器的調用將會返回同一個實例:數組

$this->app->singleton('FooBar', function ($app) {    return new FooBar($app['SomethingElse']);
});

綁定實例閉包

你還可使用instance方法綁定一個已存在的對象實例到容器,隨後對容器的調用將老是返回給定的實例:app

$fooBar = new FooBar(new SomethingElse);$this->app->instance('FooBar', $fooBar);

2.1 綁定接口到實現

服務容器的一個很是強大的特性是其綁定接口到實現的能力。咱們假設有一個EventPusher接口及其RedisEventPusher實現,編寫完該接口的RedisEventPusher實現後,就能夠將其註冊到服務容器:函數

$this->app->bind('App\Contracts\EventPusher', 'App\Services\RedisEventPusher');

這段代碼告訴容器當一個類須要EventPusher的實現時將會注入RedisEventPusher,如今咱們能夠在構造器或者任何其它經過服務容器注入依賴的地方進行EventPusher接口的類型提示:post

use App\Contracts\EventPusher;/**
 * 建立一個新的類實例
 *
 * @param  EventPusher  $pusher
 * @return void
 */public function __construct(EventPusher $pusher){    $this->pusher = $pusher;
}

2.2 上下文綁定

有時侯咱們可能有兩個類使用同一個接口,但咱們但願在每一個類中注入不一樣實現,例如,當系統接到一個新的訂單的時候,咱們想要經過PubNub而不是Pusher發送一個事件。Laravel定義了一個簡單、平滑的方式來定義這種行爲:this

$this->app->when('App\Handlers\Commands\CreateOrderHandler')
          ->needs('App\Contracts\EventPusher')
          ->give('App\Services\PubNubEventPusher');

你甚至還能夠傳遞一個閉包到give方法:spa

$this->app->when('App\Handlers\Commands\CreateOrderHandler')
          ->needs('App\Contracts\EventPusher')
          ->give(function () {                  // Resolve dependency...
              });

2.3 標籤

少數狀況下咱們須要解析特定分類下的全部綁定,好比,也許你正在構建一個接收多個不一樣Report接口實現的報告聚合器,在註冊完Report實現以後,能夠經過tag方法給它們分配一個標籤:

$this->app->bind('SpeedReport', function () {    //});$this->app->bind('MemoryReport', function () {    //});$this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');

這些服務被打上標籤後,能夠經過tagged方法來輕鬆解析它們:

$this->app->bind('ReportAggregator', function ($app) {    return new ReportAggregator($app->tagged('reports'));
});

三、解析

有不少方式能夠從容器中解析對象,首先,你可使用make方法,該方法接收你想要解析的類名或接口名做爲參數:

$fooBar = $this->app->make('FooBar');

其次,你能夠以數組方式訪問容器,由於其實現了PHP的ArrayAccess接口:

$fooBar = $this->app['FooBar'];

最後,也是最經常使用的,你能夠簡單的經過在類的構造函數中對依賴進行類型提示來從容器中解析對象,包括控制器事件監聽器隊列任務中間件等都是經過這種方式。在實踐中,這是大多數對象從容器中解析的方式。

容器會自動爲其解析類注入依賴,好比,你能夠在控制器的構造函數中爲應用定義的倉庫進行類型提示,該倉庫會自動解析並注入該類:

<?phpnamespace App\Http\Controllers;use Illuminate\Routing\Controller;use App\Users\Repository as UserRepository;class UserController extends Controller{    /**
     * 用戶倉庫實例
     */
    protected $users;    /**
     * 建立一個控制器實例
     *
     * @param  UserRepository  $users
     * @return void
     */
    public function __construct(UserRepository $users)
    {        $this->users = $users;
    }    /**
     * 經過指定ID顯示用戶
     *
     * @param  int  $id
     * @return Response
     */
    public function show($id)
    {        //
    }
}

四、容器事件

服務容器在每一次解析對象時都會觸發一個事件,可使用resolving方法監聽該事件:

$this->app->resolving(function ($object, $app) {    // 容器解析全部類型對象時調用});$this->app->resolving(function (FooBar $fooBar, $app) {    // 容器解析「FooBar」對象時調用});

正如你所看到的,被解析的對象將會傳遞給回調,從而容許你在對象被傳遞給消費者以前爲其設置額外屬性。

相關文章
相關標籤/搜索