Fusic Tech Blog

Fusion of Society, IT and Culture

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

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

皆さまこんにちは、 Fusic チーム LIGHT の近藤です。

月に 1 回ぐらいしか出社しておらず、プライベートでも基本引きこもっているので 8 月の総歩数が 10,874 歩でした。自分の体が心配です。

チーム内で実施している Laravel 輪読会について、備忘録を綴ってまいります。

チーム LIGHT の紹介

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

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

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

LIGHTブログ

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

LIGHT Youtubeチャンネル

Laravel 輪読会の紹介

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

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

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

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@NOON~Laravelアンチパターン編~ でも少し触れているが、「どこからでも呼び出せて便利!」で Facade を作ってはいけないと再確認。

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


今回の内容は、「我々は雰囲気でサービスコンテナを使っている」状態を自覚するのに大いに役立ちました。

深堀りしようと思えばどんどん深堀りできるところなので、本を読んで楽し、ソースコードを追って楽し、ですね。

次回はサービスプロバイダと、コンストラクタまで読み進めてみる予定です。

それではまた次回!

choclucy

choclucy

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