【Laravel5.2翻譯】服務(wù)容器


前陣子看了點Laravel源碼,越看越亂,網(wǎng)上大部分中文文檔都是直譯,比較生澀難懂,還是決定看英文文檔順便就我的理解做下翻譯整理記錄下來

思維導(dǎo)圖

簡介

Laravel的服務(wù)容器是一個管理類依賴執(zhí)行依賴注入的強大工具。依賴注入是一個簡稱,它的意思是:類依賴通過構(gòu)造函數(shù)或者"setter"方法“注入”到類中。

看一個簡單的例子:

<?php

namespace App\Jobs;

use App\User;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Contracts\Bus\SelfHandling;

class PurchasePodcast implements SelfHandling
{
    /**
     * The mailer implementation.
     */
    protected $mailer;

    /**
     * Create a new instance.
     *
     * @param  Mailer  $mailer
     * @return void
     */
    public function __construct(Mailer $mailer)
    {
        $this->mailer = $mailer;
    }

    /**
     * Purchase a podcast.
     *
     * @return void
     */
    public function handle()
    {
        //
    }
}

在這個案例中,PurchasePodcast需要在padcast被購買的時候發(fā)送電子郵件。所以,我們將注入一個可以發(fā)送郵件的服務(wù)。由于服務(wù)是被注入的,我們可以方便的用其他實現(xiàn)來替換。我們也可以在測試我們應(yīng)用的時候輕松模擬,或者創(chuàng)建一個郵件的偽實現(xiàn)。

深入理解Laravel服務(wù)容器是創(chuàng)建一個大型應(yīng)用基礎(chǔ),除此之外對為Laravel核心做貢獻也很有幫助。

綁定

服務(wù)容器的綁定基本上都是在服務(wù)提供者中注冊的,所以所有這些例子都將在這個背景下演示如何使用容器。然而,如果類本身不依賴于任何接口就沒有綁定的必要。容器不需要被告之如何創(chuàng)建這些對象,因為它可以用PHP反射服務(wù)來自動處理這些實例對象。
在一個服務(wù)提供者里,我們始終通過$this->app實例變量來訪問容器。我們可以通過bind方法注冊綁定,傳入兩個參數(shù),一個是我們要注冊的類名或者接口名,還有一個就是返回類實例的閉包。

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

注意我們獲取容器本身作為參數(shù)傳給解析器。然后我們可以用容器獲得要創(chuàng)建的對象的子依賴。

綁定一個單例

singleton方法把類或接口綁定到容器中,它們只能被解析一次,然后之后進入對容器的請求都會返回同樣的實例。

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

你也可以用instance方法把一個存在的對象綁定到容器。之后的請求總是會返回這個實例對象。

$fooBar = new FooBar(new SomethingElse);

$this->app->instance('FooBar', $fooBar);
綁定接口到實現(xiàn)

服務(wù)容器的一個非常強大的特性就是它可以把接口綁定到給定實現(xiàn)。例如,我們假設(shè)我們有一個EventPusher接口和一個RedisEventPusher實現(xiàn)。我們?yōu)檫@個接口編寫完RedisEventPusher實現(xiàn)后,我們可以這樣把它注冊到服務(wù)容器:

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

這就告訴容器當(dāng)一個類需要EventPusher實現(xiàn)的時候,應(yīng)該注入RedisEventPusher?,F(xiàn)在我們在構(gòu)造函數(shù)或者任何地方用類型提示,服務(wù)容器就會在那里把依賴注入進來:

use App\Contracts\EventPusher;

/**
 * Create a new class instance.
 *
 * @param  EventPusher  $pusher
 * @return void
 */
public function __construct(EventPusher $pusher)
{
    $this->pusher = $pusher;
}
上下文綁定

有時候你可能有兩個類用到同一個接口,但你想要給它們分別注入不同的實現(xiàn)。例如,
當(dāng)我們系統(tǒng)受到一個新指令,我們可能希望通過PubNub來發(fā)送事件而不是用Pusher。Laravel提供了一個簡單,流暢的接口來定義這個行為:

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

你可以傳送一個閉包給give方法

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

有時候我們可能有一個類,它獲取了一些被注入的類,但同時需要注入一個原始變量比如Integer,你可以用上下文綁定輕松注入任何你類需要的值。

$this->app->when('App\Handlers\Commands\CreateOrderHandler')
          ->needs('$maxOrderCount')
          ->give(10);

標(biāo)簽

偶爾,你可能需要解析所有特定類別的綁定。例如,或許你正在構(gòu)建一個報告整合器,它接收一個由很多不同的Report接口實現(xiàn)組成的數(shù)組,你可以用tag方法給他們分配一個標(biāo)簽。

$this->app->bind('SpeedReport', function () {
    //
});

$this->app->bind('MemoryReport', function () {
    //
});

$this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');

當(dāng)這些服務(wù)被標(biāo)記了,你可以通過tagged方法輕松解析它們:

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

解析

有很多方法可以從容器中解析對象。第一種方法,你可以用make方法,它接受你要解析的類或者接口名:

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

第一種,你可以像數(shù)組一樣訪問容器,因為它實現(xiàn)了PHP的ArrayAccess接口:

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

最后,也是最重要的,你可以簡單地在被容器解析的類構(gòu)造函數(shù)里加上依賴的“類型提示”,這些類包括controllers,event listeners,queue jobsmiddleware等等。實際上,大部分對象都是這么被容器解析的。
容器會自動注入類依賴提供類來解析。例如,你可以在控制器的構(gòu)造函數(shù)中類型提示一個被應(yīng)用定義的倉庫。這個倉庫會自動解析和注入到這個類中。

<?php

namespace App\Http\Controllers;

use App\Users\Repository as UserRepository;

class UserController extends Controller
{
    /**
     * The user repository instance.
     */
    protected $users;

    /**
     * Create a new controller instance.
     *
     * @param  UserRepository  $users
     * @return void
     */
    public function __construct(UserRepository $users)
    {
        $this->users = $users;
    }

    /**
     * Show the user with the given ID.
     *
     * @param  int  $id
     * @return Response
     */
    public function show($id)
    {
        //
    }
}

容器事件

服務(wù)容器每解析一個對象都會觸發(fā)一次事件。你可以用resolving方法來監(jiān)聽這個事件:

$this->app->resolving(function ($object, $app) {
    // Called when container resolves object of any type...
});

$this->app->resolving(FooBar::class, function (FooBar $fooBar, $app) {
    // Called when container resolves objects of type "FooBar"...
});

你可以看到,被解析的對象會傳遞一個回調(diào),你可以在對象傳遞給用戶前在它上面設(shè)置任何額外屬性。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,568評論 19 139
  • 從三月份找實習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時芥藍閱讀 42,803評論 11 349
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,697評論 18 399
  • 今天因為十個贊的事情,好不容易能有勇氣找我男神說一下,讓他贊我十下。 沒想到很快回我了,說,贊的正好是整...
    沒被好奇心害死的貓閱讀 568評論 0 0
  • 聊微信是什么目的,為空虛尋找出口?為不尋常經(jīng)歷?還是為了找對象?這是一種浪費時間嗎?我喜歡這樣嗎?還是回歸我最熟悉...
    自隨風(fēng)閱讀 223評論 0 0

友情鏈接更多精彩內(nèi)容