サービスプロバイダー(Service Provider)を理解するためにはサービスコンテナ(Service Container)を事前に理解しておく必要があります。

サービスプロバイダーの説明の前に下記の文書を読んでいることをおすすめしています。

サービスプロバイダーとは

サービスプロバイダーの役目はサービスコンテナへのサービスの登録です。

Laravelではサービスコンテナに登録されているサービスを利用してアプリケーションの開発を行なっていきます。サービスコンテナはサービスを入れる入れ物の役割をもっており、サービスを利用するためには、サービスコンテナに事前にサービスを登録しておく必要があります。そのサービスを登録する役目をもつものがサービスプロバイダーです。

Laravelのサービスとはメール送信、暗号化やファイル操作といったLaravelアプリケーションで利用する機能です。

サービスプロバイダーを理解

サービスプロバイダーを登録する場所、登録したサービスの利用方法、最後に自分でサービスプロバイダーを作成することでサービスプロバーダーの理解を深めていきます。

サービスプロバイダーの登録場所

サービスプロバイダーを使ったサービスの登録はどこで行われているのか確認していきましょう。

ブラウザからアクセスがあるとpubicフォルダのindex.phpが実行され、bootstrapフォルダのapp.phpが読み込まれます。


$app = require_once __DIR__.'/../bootstrap/app.php';

bootstrapフォルダのapp.phpからLaravelのコアであるApplicationクラスがインスタンス化されています。


$app = new Illuminate\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);

このIlluminate\Foundation\Application.phpの中身を見るとregisterConfirureProvidersメソッドで、サービプロバイダーを登録している箇所があります。サービプロバイダーはconfig[‘app.providers’]を使って読み込まれています。


    public function registerConfiguredProviders()
    {
        $providers = Collection::make($this->config['app.providers'])
                        ->partition(function ($provider) {
                            return Str::startsWith($provider, 'Illuminate\\');
                        });

configフォルダのapp.phpを開いて、providersを確認するとサービスプロバイダーの一覧を確認することができます。


   'providers' => [

        /*
         * Laravel Framework Service Providers...
         */
        Illuminate\Auth\AuthServiceProvider::class,
        Illuminate\Broadcasting\BroadcastServiceProvider::class,
        Illuminate\Bus\BusServiceProvider::class,
        Illuminate\Cache\CacheServiceProvider::class,
        Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
        Illuminate\Cookie\CookieServiceProvider::class,
        Illuminate\Database\DatabaseServiceProvider::class,
        Illuminate\Encryption\EncryptionServiceProvider::class,
        Illuminate\Filesystem\FilesystemServiceProvider::class,

サービスプロバイダーの中身を確認

Laravelのサービスは、config/app.phpファイルに記述されているサービスプロバイダーから登録されます。

サービスプロバイダーに関する情報がconfig/app.phpにあることがわかったので、記述されているサービスプロバイダーの個別の中身を確認します。コードがわかりやすいEncryptionServiceProviderとFilesystemServiceProviderを使ってサービスプロバイダーの処理内容を確認するのがおすすめです。ここではEncryptionServiceProvider.phpを使います。

Encryptionは暗号化という意味を持ち、Encryptionは暗号化を行う際に利用するサービスです。FilesystemServiceProviderはファイルシステムのファイルを操作する際に利用するサービスです。

EncryptionServiceProvider.phpを開くとregisterメソッドの中でsingletonメソッドを使ってサービスコンテナへの登録を行なっています。

singletonメソッドは一度インスタンスを作成すると何度singletonメソッドを実行しても同じインスタンスを利用します。

public function register()
{
    $this->app->singleton('encrypter', function ($app) {
        $config = $app->make('config')->get('app');

        // If the key starts with "base64:", we will need to decode the key before handing
        // it off to the encrypter. Keys may be base-64 encoded for presentation and we
        // want to make sure to convert them back to the raw bytes before encrypting.
        if (Str::startsWith($key = $this->key($config), 'base64:')) {
            $key = base64_decode(substr($key, 7));
        }

        return new Encrypter($key, $config['cipher']);
    });
}

上記はsingletonメソッドを使ってencrypterという名前でサービスコンテナへの登録を行なっています。Encrypterクラスをインスタンス化するためには、configファイルからキーを取得する必要があるため、キーに関する処理が必要になります。

サービスコンテナへはencrypterという名前で登録されているため、このサービスを使いたいときはencrypterを下記のように記述することで使用することが可能になります。

動作確認のためにweb.phpに下記のコードを記述します。


//(1)インスタンス化
$encrypt = app()->make('encrypter');
//(2)$password変数には、eyJpdiI6IitLcEpqM0....が入る
$password = $encrypt->encrypt('password');
//(3)$password変数の文字列を復号化、結果暗号化する前のpasswordが表示
dd($encrypt->decrypt($password));

(1)によって、サービスコンテナに登録されたEncryptionサービスを利用します。Encrypterクラスはencryptメソッドによって文字列を暗号化することが可能なので、(2)で暗号化を行なっています。また、Encrypterクラスは暗号化した文字列を復号化するメソッドも持っており、(3)のdecryptメソッドで復号化しています。

サービスプロバイダーを使って、サービスコンテナの登録を行わなければ、Encryptionを使うためには毎回以下のようなコードが必要となります。


$config = $app->make('config')->get('app');

if (Str::startsWith($key = $this->key($config), 'base64:')) {
    $key = base64_decode(substr($key, 7));
}

$enctypt = new Encrypter($key, $config['cipher']);

しかし、サービスプロバイダーで登録されれば、一行で終わらせることが可能です。


$encrypt = app()->make('encrypter');

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

サービスプロバイダーの登録する場所と登録方法がわかったので、サービスプロバイダーを作って登録を行います。

サービスプロバイダーはphp artisan make:providerで作成することができます。


$ php artisan make:provider OwnServiceProvider
Provider created successfully.

実行するとapp\Providersの下にOwnServiceProvider.phpファイルが作成されます。

OwnServiceProvider.phpの中には、regiterメソッドとbootメソッドが記述されいます。


class OwnServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}

registerメソッドはサービスコンテナにサービスを登録するコードを記述します。bootメソッドは、すべてのサービスプロバイダーが読み込まれたあとに実行したいコードを記述します。

bindメソッドでサービス登録と実行

サービスプロバイダーをつかってサービスの登録を行う前にサービスコンテナへの登録方法を確認しておきます。

下記のbindメソッドを使用することでサービスコンテナへの登録が行えます。

先程はsingletonメソッドを用いましが、bindメソッドを使うとbind内でクラスをインスタンスする度に毎回異なるインスタンスを作成します。

app()->bind()メソッドはweb.phpに記述しています。もapp()がヘルパー関数のため、コントローラーなどどこに記述しても実行することができます。

app()->bind('myName', function(){
    return 'John Doe';
});

登録したmyNameというサービスを利用したい場合は、makeメソッドを使います。実行するとブラウザには、John Doeが表示されます。


$name = app()->make('myName');

dd($name);

サービスプロバーダーへのコード記述

先程作成したbindメソッドをOwnServiceProvider.phpのregisterメソッドの中に記述します。


public function register()
{

    app()->bind('myName', function(){
        return 'John Doe';
    });
            
}

bindメソッドの記述方法は別のServiceProvicerと同様に下記でも行うことができます。


$this->app->bind('myName', function(){
    return 'John Doe'; });     

これだけではサービスコンテナへの登録は行われないので、config/app.phpへの追加も忘れないで行う必要があります。app.phpを開いてOwnServiceProviderを追加します。


/*
 * Application Service Providers...
 */
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
App\Providers\OwnServiceProvider::class, //追加

web.phpに下記を追加して、ブラウザにJohn Doeが表示されればサービスプロバイダーを使ったサービスコンテナへのサービス登録は成功しています。


$name = app()->make('myName');

dd($name);

この文章を読む前まではサービスプロバイダーはわからなかった人もサービスプロバイダーの追加がこんなにも簡単だと驚いたのではないでしょうか。ここまで理解できればLaravelのコア部分であるサービスコンテナとサービスプロバイダーへの不安が解消されたと思います。