Top View


Author choclucy

Laravelのサービスコンテナ # Laravel輪読会Vol.2

2021/09/02

チーム LIGHT の紹介

チーム LIGHT は現在エンジニア 5 名、デザイナー 2 名、インターン 1 名の合計 8 人のチームです。

チーム LIGHT の雑記ブログもありますので、よかったらそちらもそうぞ。

こちらは技術的な内容ではなく、メンバーの日常のことをつらつらと書いています。

また、不定期で LIGHT@NOON という配信イベントも開催しています。

Laravel 輪読会の紹介

チーム LIGHT では、週に 1 回 1 時間、 Laravel 輪読会を実施しています。

輪読会で読む本はこちらの本です!

PHPフレームワークLaravel Webアプリケーション開発 バージョン8.x対応

2021/6/1 に発売された本で、 Laravel8 にも対応しています。

ボリュームもたっぷりな上に、 Laravel の設計やテストコードに関する内容も充実しているので、オススメです!

本題

今回読んだページはP.64 ~ P.82 の「2-2 サービスコンテナ」についてです。

サービスコンテナについて

インスタンス管理の役割を担っており、 Laravel の特徴を語るとき繰り返し出てくる「DI(依存性注入)」 もサービスコンテナのおかげです。

DI とはなんぞや? については、今回の学びではないので割愛させて頂きます。

2-2-2. バインドと解決

  • バインド:サービスコンテナに対してインスタンスの精製方法を登録すること
  • 解決: 指定されたインスタンスをサービスコンテナが生成して返すこと

2-2-3. バインド

バインドの方法として、以下の 5 つがある。

  • bind
  • bindIf
  • singleton
  • instance
  • when

それぞれの違いは書籍に詳細に書いてあるのでお読みください。

バインドを定義するのは ServiceProvider クラス。デフォルトで作成される AppServiceProvider に追記していく形でも良い。

2-2-4. 解決

解決の方法は 2 つ。

  • make メソッド
  • app ヘルパ関数

一方、バインドしていない文字列を解決する機能もあり。

2-2-5. DIとサービスコンテナ

Laravelでは、コンストラクタインジェクションや、メソッドインジェクションを使用することで、インスタンスを渡すことができる。

2-2-6. ファサード

ファサードは以下の仕組みで動く。

  1. ファサードがコールされる(例としてCongif::get()を使う)
  2. Configの実態のIlluminate\Support\Configクラスのgetメソッドが呼び出される
  3. 該当のクラスにはgetメソッドがないため、スーパークラスの__callStaticメソッドが呼ばれる
  4. __callStaticメソッド内で、getFacadeRootメソッドがインスタンスを取得し、getメソッドを実行する。

チームで話したこと

bindIf()と when() の使い所

案件などで書いたコードをざーっと眺めたものの、基本使われていない。

ServiceProvider クラスで処理をややこしくしたくないので、あまり使いたくない。

instance() の具体的な使い道とは?

使ったことがないという意見が多い中、Controller のテストでたまに使う例を挙げた。

Controller で呼び出しているあるクラスが、外部 API との連携部分を司っており、テストケースではその input と詳細に関心がない場合、等。

<?php

use Mockery as m;

class SampleControllerTest extends TestCase
{
    public function testFoo(): void
    {
        $mock = m::class(\ExternalCooperation::class);
        $mock->shouldReceive('call')->andReturn(true);
        $this->instance(\ExternalCooperation::class, $mock);

        $user = User::factory()->create();
        $response = $this->actingAs($user)->put('/foo');
    }
}

bind すべきものは何か?

公式ドキュメント曰く

There is no need to bind classes into the container if they do not depend on any interfaces. The container does not need to be instructed on how to build these objects, since it can automatically resolve these objects using reflection

Interface に依存していないなら登録する必要はない。

逆に言えば、 Interface の存在する具象クラスについては、 bind したほうが良いということだろう。

Facade について

Facade がどのようにして処理を実行しているのか、一連の流れが詳細に書いてあり、仕組みを理解できたことが良かった。

第1回LIGHT@NOONLaravelアンチパターン編 でも少し触れているが、「どこからでも呼び出せて便利!」で Facade を作ってはいけないと再確認。

実質的にグローバルヘルパーと変わらない存在なので、量産する前にサービスコンテナと Facade どちらで実装するか、判断する必要がある。

choclucy

choclucy

PHP(Laravel/CakePHP) を書いています。