跳轉至內容

服務提供者

簡介

服務提供者是所有 Laravel 應用程式引導啟動的中心。你自己的應用程式以及所有 Laravel 的核心服務都是透過服務提供者引導啟動的。

但是,“引導啟動”(bootstrapped)是什麼意思呢?通常,我們指的是註冊,包括註冊服務容器繫結、事件監聽器、中介軟體,甚至是路由。服務提供者是配置應用程式的核心場所。

Laravel 在內部使用了數十個服務提供者來引導其核心服務,例如郵件傳送、佇列、快取等。其中許多提供者是“延遲”(deferred)提供者,這意味著它們不會在每個請求中載入,而僅在真正需要它們提供的服務時才會載入。

所有使用者定義的服務提供者都在 bootstrap/providers.php 檔案中註冊。在接下來的文件中,你將學習如何編寫自己的服務提供者並將其註冊到 Laravel 應用程式中。

如果你想深入瞭解 Laravel 如何處理請求及其內部工作原理,請檢視關於 Laravel 請求生命週期 的文件。

編寫服務提供者

所有服務提供者都繼承自 Illuminate\Support\ServiceProvider 類。大多數服務提供者包含一個 register 方法和一個 boot 方法。在 register 方法中,你應該只將內容繫結到 服務容器。你絕對不應該在 register 方法中嘗試註冊任何事件監聽器、路由或任何其他功能。

Artisan CLI 可以透過 make:provider 命令生成新的提供者。Laravel 會自動在應用程式的 bootstrap/providers.php 檔案中註冊你的新提供者。

1php artisan make:provider RiakServiceProvider

Register 方法

如前所述,在 register 方法中,你只能將內容繫結到 服務容器 中。你絕對不應該在 register 方法中嘗試註冊任何事件監聽器、路由或任何其他功能。否則,你可能會意外使用尚未載入的服務提供者所提供的服務。

讓我們看一個基本的服務提供者。在任何服務提供者方法中,你始終可以訪問 $app 屬性,該屬性提供了對服務容器的訪問許可權。

1<?php
2 
3namespace App\Providers;
4 
5use App\Services\Riak\Connection;
6use Illuminate\Contracts\Foundation\Application;
7use Illuminate\Support\ServiceProvider;
8 
9class RiakServiceProvider extends ServiceProvider
10{
11 /**
12 * Register any application services.
13 */
14 public function register(): void
15 {
16 $this->app->singleton(Connection::class, function (Application $app) {
17 return new Connection(config('riak'));
18 });
19 }
20}

此服務提供者僅定義了一個 register 方法,並使用該方法在服務容器中定義了 App\Services\Riak\Connection 的實現。如果你還不熟悉 Laravel 的服務容器,請查閱 相關文件

bindingssingletons 屬性

如果你的服務提供者註冊了許多簡單的繫結,你可能希望使用 bindingssingletons 屬性,而不是手動註冊每個容器繫結。當框架載入該服務提供者時,它會自動檢查這些屬性並註冊相應的繫結。

1<?php
2 
3namespace App\Providers;
4 
5use App\Contracts\DowntimeNotifier;
6use App\Contracts\ServerProvider;
7use App\Services\DigitalOceanServerProvider;
8use App\Services\PingdomDowntimeNotifier;
9use App\Services\ServerToolsProvider;
10use Illuminate\Support\ServiceProvider;
11 
12class AppServiceProvider extends ServiceProvider
13{
14 /**
15 * All of the container bindings that should be registered.
16 *
17 * @var array
18 */
19 public $bindings = [
20 ServerProvider::class => DigitalOceanServerProvider::class,
21 ];
22 
23 /**
24 * All of the container singletons that should be registered.
25 *
26 * @var array
27 */
28 public $singletons = [
29 DowntimeNotifier::class => PingdomDowntimeNotifier::class,
30 ServerProvider::class => ServerToolsProvider::class,
31 ];
32}

Boot 方法

那麼,如果我們需要在服務提供者中註冊一個 檢視合成器(view composer) 該怎麼辦?這應該在 boot 方法中完成。此方法在所有其他服務提供者都被註冊後呼叫,這意味著你可以訪問框架註冊的所有其他服務。

1<?php
2 
3namespace App\Providers;
4 
5use Illuminate\Support\Facades\View;
6use Illuminate\Support\ServiceProvider;
7 
8class ComposerServiceProvider extends ServiceProvider
9{
10 /**
11 * Bootstrap any application services.
12 */
13 public function boot(): void
14 {
15 View::composer('view', function () {
16 // ...
17 });
18 }
19}

Boot 方法依賴注入

你可以為服務提供者的 boot 方法進行依賴注入型別提示。 服務容器 會自動注入你需要的任何依賴項。

1use Illuminate\Contracts\Routing\ResponseFactory;
2 
3/**
4 * Bootstrap any application services.
5 */
6public function boot(ResponseFactory $response): void
7{
8 $response->macro('serialized', function (mixed $value) {
9 // ...
10 });
11}

註冊提供者

所有服務提供者都在 bootstrap/providers.php 配置檔案中註冊。該檔案返回一個數組,其中包含應用程式服務提供者的類名。

1<?php
2 
3return [
4 App\Providers\AppServiceProvider::class,
5];

當你呼叫 make:provider Artisan 命令時,Laravel 會自動將生成的提供者新增到 bootstrap/providers.php 檔案中。但是,如果你手動建立了提供者類,則應該手動將該提供者類新增到陣列中。

1<?php
2 
3return [
4 App\Providers\AppServiceProvider::class,
5 App\Providers\ComposerServiceProvider::class,
6];

延遲提供者

如果你的提供者服務容器 中註冊繫結,則可以選擇延遲其註冊,直到真正需要其中一個註冊的繫結時再進行載入。延遲載入此類提供者將提高應用程式的效能,因為它不會在每個請求中都從檔案系統載入。

Laravel 會編譯並存儲一份由延遲服務提供者提供的所有服務的列表,以及對應的服務提供者類名。然後,僅當你嘗試解析這些服務之一時,Laravel 才會載入該服務提供者。

要延遲提供者的載入,請實現 \Illuminate\Contracts\Support\DeferrableProvider 介面並定義一個 provides 方法。provides 方法應返回該提供者所註冊的服務容器繫結。

1<?php
2 
3namespace App\Providers;
4 
5use App\Services\Riak\Connection;
6use Illuminate\Contracts\Foundation\Application;
7use Illuminate\Contracts\Support\DeferrableProvider;
8use Illuminate\Support\ServiceProvider;
9 
10class RiakServiceProvider extends ServiceProvider implements DeferrableProvider
11{
12 /**
13 * Register any application services.
14 */
15 public function register(): void
16 {
17 $this->app->singleton(Connection::class, function (Application $app) {
18 return new Connection($app['config']['riak']);
19 });
20 }
21 
22 /**
23 * Get the services provided by the provider.
24 *
25 * @return array<int, string>
26 */
27 public function provides(): array
28 {
29 return [Connection::class];
30 }
31}