LoginSignup
87

More than 3 years have passed since last update.

Laravelの依存性の注入(DI)を具体的にどう使うのか

Last updated at Posted at 2017-10-12

※この話で利用したLaravelのバージョンは 5.4.36です。

依存性の注入(DI)についてはググればすぐにその基礎知識がわかる。

Laravelの公式ドキュメントを見れば、LaravelがDIの仕組みを持っている事がわかる。

しかしドキュメントがイマイチわかりにくく、DIを自分で使いたい場合どこに何を書けばいいのか具体的にはよくわからない。

LaravelのDIの仕組みを具体的に使ってみる

手順

  1. 入れ替わるクラスの共通メソッド名を定義するインターフェイスを作成する。
  2. そのインターフェイスをimplementsした複数のクラスを作成する。これらが環境によって入れ替わる。
  3. サービスプロバイダ設定をする。環境ごとの処理分けをここに記述する。
    • サービスプロバイダファイルを新規作成し、/config/app.php に追記する。
    • または既存のサービスプロバイダファイルに追記する。
  4. コントローラーで「Illuminate\Foundation\Application」が使用できるようにuseする。
  5. $app->make(サービスプロバイダで名付けた名前) で依存性注入されたクラスのインスタンスを取り出す。

具体例で解説

  • 猫クラスがある。
  • ジャンプするというメソッドを持つ。
  • 開発版では3メートルジャンプする。
  • 製品版では6メートルジャンプする。
  • 2種類の猫クラスを、LaravelのDI機能を利用して環境ごとに入れ替える。

1. 入れ替わるクラスの共通メソッド名を定義するインターフェイスを作成する。

/app/CatInterface.php

namespace App;

interface CatInterface
{
    public function jump();
}

2. そのインターフェイスをimplementsした複数のクラスを作成する。これらが環境によって入れ替わる。

/app/CatLocal.php

namespace App;

class CatLocal implements CatInterface
{
    public function jump(){
        return 'ローカル猫は3メートルジャンプした';
    }
}

/app/CatProduction.php

namespace App;

class CatProduction implements CatInterface
{
    public function jump(){
        return '製品猫は6メートルジャンプした';
    }
}

3. サービスプロバイダ設定をする。環境ごとの処理分けをここに記述する。

/app/Providers/CatServiceProvider.php

namespace App\Providers;
use Illuminate\Support\ServiceProvider;

class CatServiceProvider extends ServiceProvider
{
    public function boot()
    {
    }

    public function register()
    {
        //env('APP_ENV') で .env ファイルの「APP_ENV」の値が取れる
        $env = env('APP_ENV');

        switch($env){
            case('production'):
                $this->app->bind('cat', 'App\CatProduction');
                break;

            default:
                $this->app->bind('cat', 'App\CatLocal');
        }
    }
}

/config/app.php

// (省略)
    'providers' => [
        // (省略)

        //追加
        App\Providers\CatServiceProvider::class,
    ],
// (以後省略)

4. コントローラーで「Illuminate\Foundation\Application」が使用できるようにuseする。

5. $app->make(サービスプロバイダで名付けた名前) で依存性注入されたクラスのインスタンスを取り出す。

ちなみにルーティング設定
/routes/web.php

Route::get('/home', 'HomeController@index')->name('home');

/app/Http/Controllers/HomeController.php

<?php

namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Foundation\Application as Application; //DI利用のため

class HomeController extends Controller
{
    public function index(Application $app)
    {
        //App\Providers\CatServiceProvider での依存性の注入設定に従ってインスタンス化される
        $cat = $app->make('cat');
        echo($cat->jump());
    }
}

Application::getInstance()でもApplicationインスタンスを取得できるようです。

use Illuminate\Foundation\Application;
// (中略)
$app = Application::getInstance();

実験結果

.env の「APP_ENV」の値が「local」のとき

スクリーンショット 2017-10-12 12.21.27.png

.env の「APP_ENV」の値が「production」のとき

スクリーンショット 2017-10-12 12.21.00.png

ちょっと解説

自分の理解している範囲での解説です。

  • Laravelでは依存性の注入の実現のために「サービスコンテナ」という仕組みを使っているらしい。
  • サービスコンテナというのはサービスを入れてまとめる箱のようなものらしい。
  • サービスというのは「メールを送信する」「ユーザーを認証する」みたいな個々の機能。
  • サービスプロバイダというのは個々の機能を具体的に実現するクラスのこと。
  • 「この名前でこのクラスを登録しておくよ」「指定した名前を経由して登録されたクラスを取り出すよ」ということができるようになっている。

サービスコンテナ

  • 公式ドキュメントでの解説では $this->app という名前の変数でよく登場する。
  • その実態は Illiminate\Foundation\Application クラスのインスタンスである。
  • サービスプロバイダファイル内では $this->app がいきなり使えるが、コントローラーファイル内ではuseしないと使えない。
  • $this->app->bind(任意の名前, 紐付けられるクラス) で任意の名前と実際に働くクラスとを紐付けする。
  • $this->app->make(任意の名前) で取り出す。

追記

コメントにてよりスマートなやり方を紹介いただきました。

su_miさんのコメントをぜひご覧ください。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
87