第02回: Service Provider設計 — AppServiceProviderに「何でも書く」のはなぜ危ないのか?

章: 第1章: Laravel内部と設計基盤

プロジェクトが成長するにつれて、AppServiceProviderregister() がどんどん膨らんでいく――これは多くのLaravelプロジェクトで起きる「初期化処理の肥大化」です。依存登録・イベント購読・ポリシー登録が一か所に混在すると、変更のたびに影響範囲が読めなくなります。

Service Providerを 関心ごとに分割して設計する ことで、初期化処理の見通しが劇的に改善します。アプリが起動するまでの流れを把握し、「誰が・何を・いつ登録するか」を明確にしていきましょう。

なぜService Provider設計が重要なのか

AppServiceProvider に集中させると次の問題が起きます。

  • どのProviderが何を登録しているか追いにくくなる
  • boot() の処理順序が把握できず、初期化タイミングのバグが生じる
  • 機能単位での削除・差し替えが困難になる

チェックポイント: register() はサービスのバインドのみ、boot() はバインド済みサービスを使った処理のみ。この区分を守るだけで設計が安定します。

register vs boot — 何をどちらに書くか

処理の種類 register() boot()
コンテナへのバインド
ルーティング定義
イベントリスナー登録
ポリシー登録
他のサービスへのアクセス ❌(未解決の可能性)

実装例


<?php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Contracts\Clock;
use App\Services\SystemClock;

class DomainServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(Clock::class, SystemClock::class);
    }

    public function boot(): void
    {
        // 起動後フック
    }
}

Providerの分割指針

Providerを分けるときは「ドメイン単位」か「インフラ単位」を基準にすると迷いが減ります。

  • DomainServiceProvider — ビジネスロジック層の依存解決
  • InfrastructureServiceProvider — 外部API・ストレージの差し込み
  • EventServiceProvider — イベントとリスナーの対応表

AppServiceProvider は最小限に保ち、役割が増えたら専用Providerに切り出す習慣をつけましょう。

まとめ & 次のステップ

  • Service Providerはアプリ起動時の初期化を担う「設定の窓口」
  • register() はバインドのみ、boot() はバインド後の処理のみ ― この区分を徹底する
  • AppServiceProvider への集中は避け、関心ごとにProviderを分割する
  • config/app.phpproviders 配列で登録順を管理できることも意識しておく

次回は 第03回: ミドルウェアパイプライン詳細 で、HTTPリクエストがコントローラに届くまでの処理経路を学びます。

Related Articles