【Laravel】 サービスプロバイダを理解して作る

サービスプロバイダは、その名の通りサービスを提供するものです。

サービスプロバイダとは

Laravelから最初に入っているサービスプロバイダがそのまま例になります。

例えば、EventServiceProviderは、イベントを発行したら紐付けたクラスのインスタンスを生成してイベントを投げる、という機能を提供しています。

RouteServiceProviderは、ルーティングにおいて特定のグループに特定のミドルウェアを付ける、スロットリングを行うなどの機能を提供しています。

そういった、バックエンドで開発者向けに機能を提供するのがサービスプロバイダです。Laravelでは、初期化時にどんな風に設定するかがしばしば書かれ、サービスコンテナを利用します。

つまり、初期化時に何かしらの設定を行い、実際に動作する際にサービスコンテナを利用して機能を使う、といったときに役立つことが多いと思います。

サービスプロバイダを作る

早速サービスプロバイダを作ってみましょう。

registerとboot

サービスコンテナでは、registerbootメソッドの2つが主役です。registerではサービスコンテナへの登録のみを行い、bootではそのサービスプロバイダ固有の処理を行います。

registerで登録以外の処理を行おうとしても、その時点ではまだ利用できない機能が多くあるため、動作しない可能性があるので注意が必要です。

クラス作成と登録

クラスを作るには、artisanを使用するのが手っ取り早いです。

php artisan make:provider EncryptServiceProvider

作成したら、そのサービスプロバイダを利用できるように登録する必要があります。登録するには、config/app.phpprovidersに記述します。

config/app.php
use Illuminate\Support\Facades\Facade;

return [
    // ...
    'providers' => [
        // ...
        App\Providers\EncryptServiceProvider::class,
    ]
]

定義しても、そのままでは反映されません。php artisan optimizeしてキャッシュをクリアする必要があります。

registerを実装

registerでは、サービスコンテナに登録する処理を記述します。

public function register()
{
    $this->app->bind('encrypt.aes256', function ($app, $context) {
        Log::debug($context['text']);
        return "hoge";
    });
}

バインドとシングルトンの定義はregisterに記述する必要はなく、$bindings$singletonsに配列で並べることもできます。(無名関数は並べられません)

class EncryptServiceProvider extends ServiceProvider
{
    // $this->app->bind の代わり
    public $bindings = [
        IFooService::class => FugaService::class,,
        'abcde' => HigeService::class,
        // ...
    ];

    // $this->app->singleton の代わり
    public $singletons = [
        HogeService::class => HogeService::class,
        // ...
    ];

    // ...
}

bootを定義

bootでは、他のサービスプロバイダで登録完了後に呼ばれます。そのため、様々な処理を行うことができます。

また、bootの仮引数にタイプヒントを付けることで、サービスコンテナが適切なオブジェクトを注入してくれます。

public function boot(HogeService $hoge)
{
    $hoge->outputLog();
}

遅延読み込み

もしサービスプロバイダがサービスコンテナへの登録のみを行う場合、実際に利用しない限りはそのサービスプロバイダをロードする必要は無いはずです。

その場合、DeferrableProviderimplementし、providesを作成して何を要求されたらサービスをロードするかを書きます。

namespace App\Providers;

use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\ServiceProvider;

class EncryptServiceProvider extends ServiceProvider implements DeferrableProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind('encrypt.aes256', function ($app, $context) {
            Log::debug($context['text']);
            return "hoge";
        });
    }

    public function provides()
    {
        return ['encrypt.aes256'];
    }
}

遅延読み込みできているかは、register内でLog::debugでログを出すなどをすると判別できます。

php artisan optimizeしても遅延読み込みが反映されない場合、php artisan clear-compiledphp artisan config:cacheすると直ると思います。

まとめ

サービスプロバイダは、サービスコンテナを使用して様々な機能を提供するためのものです。registerではサービスコンテナへの登録処理のみを行うということを把握しておきましょう。

laravel provider thumb

役に立ったらシェアしよう!