[Laravel 5.6 ~] ServiceProvider内でシンプルなbindを行う方法が増えてた


はじめに

初投稿です。

今まで業務ではlaravel5.5を使っており、最近新規のプロジェクトでlaravel6系統を使うようになったので、色々と変更点を確認しておりました(今更)。

その中で、ドキュメントにひっそりと追記されているにもかかわらず、あまり類似の情報をqiita等で見かけなかった(と思っている)物があったため、備忘録として投稿します。

環境

  • laravel 5.6 ~
    • ~ 5.5までは対応していません

対象

  • Laravelをそれなりに使っていて、DIコンテナ内で抽象と具象のbindについて大枠理解している方
    • 本記事ではDIの仕組み、それを使う動機等、「そもそもなぜこんなことをする必要があるか」について理解されている前提です。

基本的なバインド処理

さて、早速ですが基本的なバインド処理についてです。
最も基本的なinterfaceと実装クラスのbindingは以下のようになるかと思います。

app/Providers/AppServiceProvider.php

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        // 抽象に対して具象クラスをbindingする
        // 以後、コンストラクタインジェクションやapp()の引数に(Abstract::class)で呼び出すと、Concreteクラスが返却される
        $this->app->bind(Abstract::class, Concrete::class);
        dd(Abstract::class); // => Concreteクラスが返却される
    }

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

~ 5.5までのバインド方法

その上で、複数のバインドをまとめて行いたいユースケースについて考えます。
今まで自分が関わってきたプロジェクトで、バインドを複数まとめて行いたいとき(Repository Pattern等)、以下のような書き方をしていました。

app/Providers/AppServiceProvider.php
class AppServiceProvider extends ServiceProvider
{
    /**
     * bindingするinterfaceと実装クラスを$key => $valueで保持する
     *
     * @param array
     */
    private $repositoryBindings = [
        FooRepository::class => EloquentFooRepository::class,
        BarRepository::class => EloquentBarRepository::class,
    ];

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        // すべてのbindingを回して登録する
        foreach($repositoryBindings as $abstract => $concrete) {
            $this->app->bind($abstract => $concrete);
        }
    }

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

汚いというわけでもなく、特に問題なく動作するコードです。

5.6からのバインド方法

readoubleにしれっと追記されています。
https://readouble.com/laravel/5.6/ja/providers.html

シンプルなバインドを行うためのプロパティが追加されており、ここにbindを指定するだけで自動でbindingが行われる様になっています。
(ついでに$singletonのプロパティも用意されています)

app/Providers/AppServiceProvider.php
class AppServiceProvider extends ServiceProvider
{
    /**
     * 結合したいabstractとconcreteを登録. ここに記述されたものは自動でbindingされる
     *
     * @param array
     */
    public $bindings = [
        FooRepository::class => EloquentFooRepository::class,
        BarRepository::class => EloquentBarRepository::class,
    ];

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        // ここで何も書かなくても$bindingsに指定があれば自動でbindが行われる
    }

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

終わりに

大きなメリットがあるわけでもなく、ちょっとしたtipsでした。
ただ、やはりフレームワークが用意してくれている方式に乗っかれると気持ちがいいですね。