簡介
- Laravel 服務(wù)容器是一個用于管理類的依賴和執(zhí)行依賴注入的強大工具盖淡。
- 依賴注入這個花哨名詞實質(zhì)上是指:類的依賴通過構(gòu)造函數(shù)债朵,或者某些情況下通過 "setter" 方法 "注入" 到類中圃庭。
- 這種注入方式的便利之處還體現(xiàn)在當我們?yōu)閼?yīng)用編寫測試時吏颖,我們還可以輕松地 "模擬" 或創(chuàng)建 UserRepository 的虛擬實現(xiàn)。
綁定
綁定基礎(chǔ)(不理解)
幾乎所有的服務(wù)容器綁定都是在 服務(wù)容器, 所以文檔中大多數(shù)例子都是使用了在服務(wù)提供器中綁定的容器季希。
簡單綁定
在服務(wù)提供器中褪那,你總是可以通過 $this->app
屬性訪問容器。我們可以通過容器的 bind
方法注冊綁定式塌,bind
方法的第一個參數(shù)為要綁定的類/接口名博敬,第二個參數(shù)是一個返回類實例的 Closure
:
$this->app->bind('HelpSpot\API', function ($app) {
return new HelpSpot\API($app->make('HttpClient'));
});
綁定一個單例
singleton
方法將類或接口綁定到只解析一次的容器中。一旦單例綁定被解析峰尝,相同的對象實例會在隨后的調(diào)用中返回到容器中:
$this->app->singleton('HelpSpot\API', function ($app) {
return new HelpSpot\API($app->make('HttpClient'));
});
綁定實例
你也可以使用 instance
方法將現(xiàn)有對象實例綁定到容器中偏窝。給定的實例會始終在隨后的調(diào)用中返回到容器中:
$api = new HelpSpot\API(new HttpClient);
$this->app->instance('HelpSpot\API', $api);
綁定基本值
當你有一個類不僅需要接受一個注入類,還需要注入一個基本值(比如整數(shù))武学。你可以使用上下文綁定來輕松注入你的類需要的任何值:
$this->app->when('App\Http\Controllers\UserController')
->needs('$variableName')
->give($value);
綁定接口到實現(xiàn)
服務(wù)容器有一個很強大的功能祭往,就是支持綁定接口到給定的實現(xiàn)。例如火窒,如果我們有個 EventPusher
接口 和一個 RedisEventPusher
實現(xiàn)硼补。一旦我們寫完了 EventPusher
接口的 RedisEventPusher
實現(xiàn),我們就可以在服務(wù)容器中注冊它熏矿,像這樣:
$this->app->bind(
'App\Contracts\EventPusher',
'App\Services\RedisEventPusher'
);
這么做相當于告訴容器:當一個類需要實現(xiàn) EventPusher
時已骇,應(yīng)該注入 RedisEventPusher。現(xiàn)在我們就可以在構(gòu)造函數(shù)或者任何其他通過服務(wù)容器注入依賴項的地方使用類型提示注入 EventPusher
接口:
use App\Contracts\EventPusher;
/**
* 創(chuàng)建新的類實例
*
* @param EventPusher $pusher
* @return void
*/
public function __construct(EventPusher $pusher)
{
$this->pusher = $pusher;
}
上下文綁定
有時你可能有兩個類使用了相同的接口票编,但你希望各自注入不同的實現(xiàn)褪储。例如,有兩個控制器可能依賴了不同的 Illuminate\Contracts\Filesystem\Filesystem
契約 實現(xiàn)栏妖。Laravel 提供了一個簡單的乱豆,優(yōu)雅的接口來定義這個行為:
use Illuminate\Support\Facades\Storage;
use App\Http\Controllers\PhotoController;
use App\Http\Controllers\VideoController;
use Illuminate\Contracts\Filesystem\Filesystem;
$this->app->when(PhotoController::class)
->needs(Filesystem::class)
->give(function () {
return Storage::disk('local');
});
$this->app->when(VideoController::class)
->needs(Filesystem::class)
->give(function () {
return Storage::disk('s3');
});
標記
有時候奖恰,你可能需要解析某個 "分類" 下的所有綁定吊趾。例如:你正在構(gòu)建一個報表的聚合器宛裕,它接收一個包含不同 Report
接口實現(xiàn)的數(shù)組。注冊了 Report
實現(xiàn)之后论泛,你可以使用 tag
方法為它們分配標簽:
$this->app->bind('SpeedReport', function () {
//
});
$this->app->bind('MemoryReport', function () {
//
});
$this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');
一旦服務(wù)被標記揩尸,你就可以使用 tagged
方法輕松將它們?nèi)拷馕觯?/p>
$this->app->bind('ReportAggregator', function ($app) {
return new ReportAggregator($app->tagged('reports'));
});
擴展綁定
extend
方法可以修改已解析的服務(wù)。例如屁奏,當一個服務(wù)被解析后岩榆,你可以添加額外的代碼去修飾或配置這個服務(wù)。extend
方法接受一個閉包坟瓢,該閉包唯一參數(shù)就是這個服務(wù)勇边,并返回修改過的服務(wù):
$this->app->extend(Service::class, function($service) {
return new DecoratedService($service);
});
解析實例
make
方法
你可以使用 make
方法從容器中解析出類實例。make
方法接受一個你想要解析的類名或接口名:
$api = $this->app->make('HelpSpot\API');
如果你的代碼處于無法訪問 $app
變量的位置折联,則可用全局輔助函數(shù) resolve
來解析:
$api = resolve('HelpSpot\API');
如果你的類依賴不能通過容器來解析粒褒,你可以通過將它們作為關(guān)聯(lián)數(shù)組傳遞到 makeWith
方法來注入它們:
$api = $this->app->makeWith('HelpSpot\API', ['id' => 1]);
自動注入
另外,并且更重要的是诚镰,你可以簡單地使用"類型提示"的方式在類的構(gòu)造函數(shù)中注入那些需要容器解析的依賴項奕坟,包括 控制器, 事件監(jiān)聽器, 隊列任務(wù), 中間件等。實際上清笨,這才是大多數(shù)對象應(yīng)該被容器解析的方式月杉。
容器事件
服務(wù)容器每次解析對象時會觸發(fā)一個事件,你可以使用 resolving
方法監(jiān)聽這個事件:
$this->app->resolving(function ($object, $app) {
// Called when container resolves object of any type...
});
$this->app->resolving(HelpSpot\API::class, function ($api, $app) {
// Called when container resolves objects of type "HelpSpot\API"...
});
被解析的對象將被傳入回調(diào)函數(shù)抠艾,這使得你能夠在對象被傳給調(diào)用者之前給它設(shè)置額外的屬性苛萎。
PSR-11
Laravel 的服務(wù)容器實現(xiàn)了 PSR-11 接口。 因此检号,你可以使用 PSR-11容器『接口類型提示』來獲取 Laravel 容器的實例:
use Psr\Container\ContainerInterface;
Route::get('/', function (ContainerInterface $container) {
$service = $container->get('Service');
//
});
{note} 如果標識符還沒有被顯式綁定到容器首懈,那么調(diào)用 get 方法將會拋出異常。
總結(jié)
這一篇目前沒理解到什么東西啊谨敛,回頭要看