LaravelDocs(中文)

服務提供者 (Service Providers)

Service Providers

簡介 (Introduction)

Service Providers 是所有 Laravel 應用程式啟動的中心位置。您自己的應用程式以及 Laravel 的所有核心服務都是透過 Service Providers 啟動的。

但是,「啟動」是什麼意思?一般來說,我們的意思是 註冊 事物,包括註冊 Service Container 綁定、Event Listeners、Middleware 甚至路由。Service Providers 是設定應用程式的中心位置。

Laravel 內部使用數十個 Service Providers 來啟動其核心服務,例如 Mailer、Queue、Cache 等。其中許多 Providers 是「延遲 (deferred)」Providers,這意味著它們不會在每次請求時載入,而僅在實際需要它們提供的服務時才載入。

所有使用者定義的 Service Providers 都在 bootstrap/providers.php 檔案中註冊。在以下文件中,您將學習如何編寫自己的 Service Providers 並將它們註冊到您的 Laravel 應用程式中。

[!NOTE] 如果您想了解更多關於 Laravel 如何處理請求和內部運作的資訊,請查看我們關於 Laravel 請求生命週期 的文件。

編寫 Service Providers (Writing Service Providers)

所有 Service Providers 都繼承 Illuminate\Support\ServiceProvider 類別。大多數 Service Providers 包含 registerboot 方法。在 register 方法中,您應該 只將事物綁定到 Service Container。您永遠不應嘗試在 register 方法中註冊任何 Event Listeners、路由或任何其他功能。

Artisan CLI 可以透過 make:provider 指令生成新的 Provider。Laravel 將自動在您的應用程式的 bootstrap/providers.php 檔案中註冊您的新 Provider:

php artisan make:provider RiakServiceProvider

Register 方法 (The Register Method)

如前所述,在 register 方法中,您應該只將事物綁定到 Service Container 中。您永遠不應嘗試在 register 方法中註冊任何 Event Listeners、路由或任何其他功能。否則,您可能會意外使用尚未載入的 Service Provider 提供的服務。

讓我們來看一個基本的 Service Provider。在您的任何 Service Provider 方法中,您始終可以存取 $app 屬性,該屬性提供對 Service Container 的存取:

<?php

namespace App\Providers;

use App\Services\Riak\Connection;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\ServiceProvider;

class RiakServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        $this->app->singleton(Connection::class, function (Application $app) {
            return new Connection(config('riak'));
        });
    }
}

此 Service Provider 僅定義了一個 register 方法,並使用該方法在 Service Container 中定義 App\Services\Riak\Connection 的實作。如果您還不熟悉 Laravel 的 Service Container,請查看 其文件

bindingssingletons 屬性 (The Bindings And Singletons Properties)

如果您的 Service Provider 註冊了許多簡單的綁定,您可能希望使用 bindingssingletons 屬性,而不是手動註冊每個 Container 綁定。當框架載入 Service Provider 時,它會自動檢查這些屬性並註冊它們的綁定:

<?php

namespace App\Providers;

use App\Contracts\DowntimeNotifier;
use App\Contracts\ServerProvider;
use App\Services\DigitalOceanServerProvider;
use App\Services\PingdomDowntimeNotifier;
use App\Services\ServerToolsProvider;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * All of the container bindings that should be registered.
     *
     * @var array
     */
    public $bindings = [
        ServerProvider::class => DigitalOceanServerProvider::class,
    ];

    /**
     * All of the container singletons that should be registered.
     *
     * @var array
     */
    public $singletons = [
        DowntimeNotifier::class => PingdomDowntimeNotifier::class,
        ServerProvider::class => ServerToolsProvider::class,
    ];
}

Boot 方法 (The Boot Method)

那麼,如果我們需要在 Service Provider 中註冊 View Composer 怎麼辦?這應該在 boot 方法中完成。此方法在所有其他 Service Providers 註冊後呼叫,這意味著您可以存取框架已註冊的所有其他服務:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;

class ComposerServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        View::composer('view', function () {
            // ...
        });
    }
}

Boot 方法 Dependency Injection (Boot Method Dependency Injection)

您可以對 Service Provider 的 boot 方法的依賴進行型別提示。Service Container 將自動注入您需要的任何依賴:

use Illuminate\Contracts\Routing\ResponseFactory;

/**
 * Bootstrap any application services.
 */
public function boot(ResponseFactory $response): void
{
    $response->macro('serialized', function (mixed $value) {
        // ...
    });
}

註冊 Providers (Registering Providers)

所有 Service Providers 都在 bootstrap/providers.php 設定檔中註冊。此檔案返回一個包含應用程式 Service Providers 類別名稱的陣列:

<?php

return [
    App\Providers\AppServiceProvider::class,
];

當您呼叫 make:provider Artisan 指令時,Laravel 將自動將生成的 Provider 新增到 bootstrap/providers.php 檔案中。但是,如果您手動建立了 Provider 類別,則應手動將 Provider 類別新增到陣列中:

<?php

return [
    App\Providers\AppServiceProvider::class,
    App\Providers\ComposerServiceProvider::class, // [tl! add]
];

延遲 Providers (Deferred Providers)

如果您的 Provider Service Container 中註冊綁定,您可以選擇延遲其註冊,直到實際需要註冊的綁定之一。延遲載入此類 Provider 將提高應用程式的效能,因為它不會在每次請求時從檔案系統載入。

Laravel 編譯並儲存延遲 Service Providers 提供的所有服務的清單,以及其 Service Provider 類別的名稱。然後,只有當您嘗試解析這些服務之一時,Laravel 才會載入 Service Provider。

要延遲載入 Provider,請實作 \Illuminate\Contracts\Support\DeferrableProvider 介面並定義 provides 方法。provides 方法應返回 Provider 註冊的 Service Container 綁定:

<?php

namespace App\Providers;

use App\Services\Riak\Connection;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;

class RiakServiceProvider extends ServiceProvider implements DeferrableProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        $this->app->singleton(Connection::class, function (Application $app) {
            return new Connection($app['config']['riak']);
        });
    }

    /**
     * Get the services provided by the provider.
     *
     * @return array<int, string>
     */
    public function provides(): array
    {
        return [Connection::class];
    }
}