本文へ移動
Laravel Tips

サービスコンテナ

クラスが必要とする道具を作って渡してくれるサービスコンテナの考え方と、bind・singleton・属性による登録、取り出し方、PSR-11 の使い方を説明します。

サービスコンテナは、クラスを作って、必要な道具を渡してくれる「道具箱」のようなしくみです。クラスが仕事をするとき、ほかのクラス(道具)を使うことがよくあります。このとき、道具を自分で作らず、外から渡してもらうやり方を「依存性の注入」といいます。難しそうな名前ですが、中身は「コンストラクタ(クラスを作るときに最初に動く部分)や、値を入れるメソッド(セッター)に、必要な道具を渡す」ことです。

まず、簡単な例を見ます。

php
<?php

namespace App\Http\Controllers;

use App\Services\AppleMusic;
use Illuminate\View\View;

class PodcastController extends Controller
{
    /**
     * Create a new controller instance.
     */
    public function __construct(
        protected AppleMusic $apple,
    ) {}

    /**
     * Show information about the given podcast.
     */
    public function show(string $id): View
    {
        return view('podcasts.show', [
            'podcast' => $this->apple->findPodcast($id)
        ]);
    }
}

この例の PodcastController は、Apple Music のようなデータの置き場所から、ポッドキャスト(音声の番組)を取ってくる必要があります。そこで、番組を取ってくるサービス(AppleMusic)を、外から渡して(注入して)もらっています。外から渡されるので、テストのときは、AppleMusic を「モック」(本物の代わりに置く、にせものの部品)にかんたんに入れ替えられます。

大きなアプリを作るときや、Laravel 本体に協力するときは、サービスコンテナを深く理解することが大切です。

設定なしで作られる#

クラスが道具を必要としないときや、必要な道具がふつうのクラスだけのときは、そのクラスの作り方をコンテナに教えなくて済みます。ふつうのクラスとは、インターフェース(クラスが守る約束事だけを書いたもの。中身の処理は持たない)ではない、中身のあるクラスのことです。たとえば、routes/web.php に次のように書けます。

php
<?php

class Service
{
    // ...
}

Route::get('/', function (Service $service) {
    dd($service::class);
});

アプリの / を開くと、Service クラスが自動で作られ、ルートの処理に渡されます。大きな設定ファイルを用意しなくても、依存性の注入が使えるということです。

Laravel のアプリで書くクラスの多くは、コンテナから道具を自動で受け取ります。コントローラー、イベントのリスナー、ミドルウェアなどです。また、キューのジョブの handle メソッドにも、型を書いておくだけで道具を受け取れます。

コンテナをいつ使うのか#

設定なしで作られるので、ふだんはコンテナを意識せずに、ルート・コントローラー・リスナーなどに型を書くだけで道具を受け取れます。たとえば、ルートに Illuminate\Http\Request の型を書けば、いまのリクエストが手に入ります。コンテナを直接さわらなくても、裏ではコンテナが受け渡しをしています。

php
use Illuminate\Http\Request;

Route::get('/', function (Request $request) {
    // ...
});

自動の注入とファサードのおかげで、コンテナへの登録や取り出しを一度も自分でしなくても、Laravel のアプリは作れることが多いです。では、いつコンテナを自分で使うのでしょうか。次の2つの場面があります。

  1. インターフェース(クラスが守る約束事)を実装したクラスを書き、そのインターフェースの型をルートやコンストラクタに書きたいとき。インターフェースをどのクラスにするかを、コンテナに教える必要があります
  2. ほかの Laravel の開発者に配るためのパッケージを作るとき。パッケージのサービスを、コンテナに登録する必要があります

登録する(バインディング)#

登録の基本#

コンテナへの登録は、ほとんどがサービスプロバイダ(アプリの起動のときに、道具箱へ道具を登録する場所)の中に書きます。以下の例も、その前提です。

基本の登録(bind)#

サービスプロバイダの中では、いつでも $this->app でコンテナを使えます。登録には bind メソッドを使います。渡すものは2つです。登録したいクラスかインターフェースの名前と、そのインスタンス(クラスから作った実物。オブジェクトともいいます)を作って返すクロージャ(名前のない関数)です。

php
use App\Services\Transistor;
use App\Services\PodcastParser;
use Illuminate\Contracts\Foundation\Application;

$this->app->bind(Transistor::class, function (Application $app) {
    return new Transistor($app->make(PodcastParser::class));
});

クロージャの引数には、コンテナ自身が渡されます。これを使えば、作ろうとしているものが必要とする道具も、コンテナに作らせられます。

サービスプロバイダの外でコンテナを使いたいときは、App ファサードを使います。

php
use App\Services\Transistor;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\App;

App::bind(Transistor::class, function (Application $app) {
    // ...
});

bindIf は、その型の登録がまだ無いときだけ登録します。

php
$this->app->bindIf(Transistor::class, function (Application $app) {
    return new Transistor($app->make(PodcastParser::class));
});

クラスやインターフェースの名前を別の引数で書かなくても、クロージャの戻り値の型から Laravel が読み取ってくれます。

php
App::bind(function (Application $app): Transistor {
    return new Transistor($app->make(PodcastParser::class));
});

補足

インターフェースに頼らないクラスは、コンテナへ登録する必要がありません。リフレクション(クラスの中身を調べる PHP の機能)で、自動で作れるからです。

シングルトンの登録(singleton)#

singleton は、一度だけ作るクラスやインターフェースを登録します(シングルトンは「1つきり」という意味)。一度作ったあとは、コンテナから何度取り出しても、同じオブジェクトが返ります。

php
use App\Services\Transistor;
use App\Services\PodcastParser;
use Illuminate\Contracts\Foundation\Application;

$this->app->singleton(Transistor::class, function (Application $app) {
    return new Transistor($app->make(PodcastParser::class));
});

singletonIf は、その型の登録がまだ無いときだけ、シングルトンとして登録します。

php
$this->app->singletonIf(Transistor::class, function (Application $app) {
    return new Transistor($app->make(PodcastParser::class));
});

Singleton 属性#

クラスやインターフェースに #[Singleton] という PHP の属性(クラスやメソッドの前に書く印)を付けても、一度だけ作る指定になります。

php
<?php

namespace App\Services;

use Illuminate\Container\Attributes\Singleton;

#[Singleton]
class Transistor
{
    // ...
}

スコープ付きシングルトンの登録(scoped)#

scoped は、1回のリクエストや1つのジョブを処理するあいだだけ、一度作ったものを使い回す登録です。singleton に似ていますが、Laravel が新しい処理の流れを始めるたびに、作ったものは捨てられます。新しい流れが始まるのは、たとえば Laravel Octane のワーカーが新しいリクエストを扱うときや、キューのワーカーが新しいジョブを扱うときです。

php
use App\Services\Transistor;
use App\Services\PodcastParser;
use Illuminate\Contracts\Foundation\Application;

$this->app->scoped(Transistor::class, function (Application $app) {
    return new Transistor($app->make(PodcastParser::class));
});

scopedIf は、その型の登録がまだ無いときだけ、スコープ付きとして登録します。

php
$this->app->scopedIf(Transistor::class, function (Application $app) {
    return new Transistor($app->make(PodcastParser::class));
});

Scoped 属性#

#[Scoped] 属性を付けても、1回のリクエスト・ジョブの流れのあいだだけ一度作る指定になります。

php
<?php

namespace App\Services;

use Illuminate\Container\Attributes\Scoped;

#[Scoped]
class Transistor
{
    // ...
}

作ってあるインスタンスの登録(instance)#

自分で作ったオブジェクトを、instance でコンテナに登録できます。そのあとは、取り出すたびに、登録したそのオブジェクトが返ります。

php
use App\Services\Transistor;
use App\Services\PodcastParser;

$service = new Transistor(new PodcastParser);

$this->app->instance(Transistor::class, $service);

登録のメソッドのまとめ#

メソッド・属性 説明
bind クラス・インターフェースを登録する。singleton と違い、1回きりにはしない
bindIf その型の登録が無いときだけ登録する
singleton 一度だけ作り、同じものを返す
singletonIf 登録が無いときだけ、シングルトンとして登録する
scoped 1回のリクエスト・ジョブの流れのあいだだけ、一度作る
scopedIf 登録が無いときだけ、スコープ付きとして登録する
instance 作ってあるオブジェクトを登録する
#[Singleton] 属性で、一度だけ作る指定をする
#[Scoped] 属性で、1回の流れのあいだだけ一度作る指定をする

インターフェースを実装に結びつける#

サービスコンテナのとても強い機能が、インターフェースを、その中身を書いたクラス(実装)に結びつけることです。たとえば、EventPusher というインターフェースと、その実装の RedisEventPusher があるとします。実装を書いたら、コンテナに次のように登録します。

php
use App\Contracts\EventPusher;
use App\Services\RedisEventPusher;

$this->app->bind(EventPusher::class, RedisEventPusher::class);

これは、「EventPusher の実装が必要になったら、RedisEventPusher を渡す」という指示です。これで、コンテナが作るクラスなら、コンストラクタに EventPusher の型を書くだけで受け取れます。コントローラー・リスナー・ミドルウェアなどは、いつもコンテナが作っています。

php
use App\Contracts\EventPusher;

/**
 * Create a new class instance.
 */
public function __construct(
    protected EventPusher $pusher,
) {}

Bind 属性#

もっと手軽な Bind 属性もあります。インターフェースに付けておくと、そのインターフェースを求められたときに、どの実装を自動で渡すかを決められます。サービスプロバイダに登録を書かなくて済みます。

インターフェースに Bind 属性を複数付けて、環境ごとに別の実装を渡すこともできます。

php
<?php

namespace App\Contracts;

use App\Services\FakeEventPusher;
use App\Services\RedisEventPusher;
use Illuminate\Container\Attributes\Bind;

#[Bind(RedisEventPusher::class)]
#[Bind(FakeEventPusher::class, environments: ['local', 'testing'])]
interface EventPusher
{
    // ...
}

Singleton と Scoped の属性も、いっしょに付けられます。「一度だけ作る」か「1回のリクエスト・ジョブの流れで一度作る」かを指定できます。

php
use App\Services\RedisEventPusher;
use Illuminate\Container\Attributes\Bind;
use Illuminate\Container\Attributes\Singleton;

#[Bind(RedisEventPusher::class)]
#[Singleton]
interface EventPusher
{
    // ...
}

好きな条件で決めたいときは、BindWhen 属性を使います。条件はクロージャで書きます。クロージャはコンテナを受け取れて、その実装を使うときに true を返すようにします。Bind と BindWhen は、書いた順に調べられます。

php
use App\Services\BetaEventPusher;
use Illuminate\Container\Attributes\BindWhen;
use Laravel\Pennant\Feature;

#[BindWhen(BetaEventPusher::class, static fn () => Feature::active('beta-events'))]
interface EventPusher
{
    // ...
}

補足

BindWhen 属性は、PHP 8.5 以上が必要です。

場面ごとの登録(コンテキストバインディング)#

同じインターフェースを使う2つのクラスに、別々の実装を渡したいことがあります。たとえば、2つのコントローラーが、Illuminate\Contracts\Filesystem\Filesystem というコントラクト(Laravel が用意したインターフェース)の、それぞれ別の実装を使いたい場合です。次のように、メソッドをつないでかんたんに書けます。

php
use App\Http\Controllers\PhotoController;
use App\Http\Controllers\UploadController;
use App\Http\Controllers\VideoController;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Support\Facades\Storage;

$this->app->when(PhotoController::class)
    ->needs(Filesystem::class)
    ->give(function () {
        return Storage::disk('local');
    });

$this->app->when([VideoController::class, UploadController::class])
    ->needs(Filesystem::class)
    ->give(function () {
        return Storage::disk('s3');
    });

場面ごとの属性(コンテキスト属性)#

場面ごとの登録は、ドライバー(使う方式)や設定値を渡すのによく使われます。そこで Laravel には、こうした値を渡すための属性がいくつかあります。属性なら、サービスプロバイダに登録を書かなくて済みます。たとえば、Storage 属性で、特定のストレージのディスクを渡せます。

php
<?php

namespace App\Http\Controllers;

use Illuminate\Container\Attributes\Storage;
use Illuminate\Contracts\Filesystem\Filesystem;

class PhotoController extends Controller
{
    public function __construct(
        #[Storage('local')] protected Filesystem $filesystem
    ) {
        // ...
    }
}

Storage のほかにも、Auth・Cache・Config・Context・DB・Give・Log・RequestAttribute・RouteParameter・Tag の属性があります。

php
<?php

namespace App\Http\Controllers;

use App\Contracts\UserRepository;
use App\Models\Organization;
use App\Models\Photo;
use App\Repositories\DatabaseRepository;
use Illuminate\Container\Attributes\Auth;
use Illuminate\Container\Attributes\Cache;
use Illuminate\Container\Attributes\Config;
use Illuminate\Container\Attributes\Context;
use Illuminate\Container\Attributes\DB;
use Illuminate\Container\Attributes\Give;
use Illuminate\Container\Attributes\Log;
use Illuminate\Container\Attributes\RequestAttribute;
use Illuminate\Container\Attributes\RouteParameter;
use Illuminate\Container\Attributes\Tag;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Cache\Repository;
use Illuminate\Database\Connection;
use Psr\Log\LoggerInterface;

class PhotoController extends Controller
{
    public function __construct(
        #[Auth('web')] protected Guard $auth,
        #[Cache('redis')] protected Repository $cache,
        #[Config('app.timezone')] protected string $timezone,
        #[Context('uuid')] protected string $uuid,
        #[Context('ulid', hidden: true)] protected string $ulid,
        #[DB('mysql')] protected Connection $connection,
        #[Give(DatabaseRepository::class)] protected UserRepository $users,
        #[Log('daily')] protected LoggerInterface $log,
        #[RequestAttribute('organization')] protected Organization $organization,
        #[RouteParameter] protected Photo $photo,
        #[Tag('reports')] protected iterable $reports,
    ) {
        // ...
    }
}
属性 説明
Storage 指定したストレージのディスクを渡す
Auth 指定した認証のガード(ログインを確かめる係)を渡す
Cache 指定したキャッシュの保存先を渡す
Config 設定値を渡す
Context 指定した名前のコンテキスト(リクエストをまたいで持ち回す情報)の値を渡す
DB 指定したデータベースの接続を渡す
Give 渡す実装を指定する
Log 指定したログの出し先を渡す
RequestAttribute いまのリクエストの属性(attribute bag)に入っている値を渡す
RouteParameter 変数の名前と同じ名前のルートのパラメーターを渡す
Tag 同じタグを付けた登録をまとめて渡す
CurrentUser ログインしている利用者を渡す

RouteParameter は、変数の名前と同じ名前のルートのパラメーターを渡します。必要なら、#[RouteParameter('photo')] のように名前を書けます。

RequestAttribute は、いまのリクエストの属性の入れ物(attribute bag)に、そのキーで入っている値を渡します。#[RequestAttribute('organization')] のように使います。

CurrentUser 属性は、ルートやクラスに、ログインしている利用者を渡します。

php
use App\Models\User;
use Illuminate\Container\Attributes\CurrentUser;

Route::get('/user', function (#[CurrentUser] User $user) {
    return $user;
})->middleware('auth');

自分で属性を作る#

Illuminate\Contracts\Container\ContextualAttribute というコントラクトを実装すれば、自分の属性も作れます。コンテナは、その属性の resolve メソッドを呼びます。このメソッドが返した値が、属性を付けた引数に渡されます。次の例は、Laravel の Config 属性を、自分で作り直したものです。

php
<?php

namespace App\Attributes;

use Attribute;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Container\ContextualAttribute;
use ReflectionParameter;

#[Attribute(Attribute::TARGET_PARAMETER)]
class Config implements ContextualAttribute
{
    /**
     * Create a new attribute instance.
     */
    public function __construct(public string $key, public mixed $default = null)
    {
    }

    /**
     * Resolve the configuration value.
     *
     * @param  self  $attribute
     * @param  \Illuminate\Contracts\Container\Container  $container
     * @param  \ReflectionParameter  $parameter
     * @return mixed
     */
    public static function resolve(self $attribute, Container $container, ReflectionParameter $parameter)
    {
        return $container->make('config')->get($attribute->key, $attribute->default);
    }
}

数字や文字を渡す(プリミティブの登録)#

クラスといっしょに、整数のような「プリミティブ」(クラスではない、ふつうの値)も受け取りたいことがあります。場面ごとの登録を使えば、どんな値でも渡せます。

php
use App\Http\Controllers\UserController;

$this->app->when(UserController::class)
    ->needs('$variableName')
    ->give($value);

タグ(目印の名前)を付けて登録したものを、配列でまとめて受け取りたいクラスもあります。giveTagged を使うと、そのタグが付いた登録をまとめて渡せます。

php
$this->app->when(ReportAggregator::class)
    ->needs('$reports')
    ->giveTagged('reports');

アプリの設定ファイルの値を渡したいときは、giveConfig を使います。

php
$this->app->when(ReportAggregator::class)
    ->needs('$timezone')
    ->giveConfig('app.timezone');

型付きの可変長引数を渡す#

コンストラクタの可変長引数(個数が決まっていない引数)で、同じ型のオブジェクトの配列を受け取るクラスがあります。

php
<?php

use App\Models\Filter;
use App\Services\Logger;

class Firewall
{
    /**
     * The filter instances.
     *
     * @var array
     */
    protected $filters;

    /**
     * Create a new class instance.
     */
    public function __construct(
        protected Logger $logger,
        Filter ...$filters,
    ) {
        $this->filters = $filters;
    }
}

この引数には、場面ごとの登録で値を渡せます。give に、作り終えた Filter の配列を返すクロージャを渡します。

php
$this->app->when(Firewall::class)
    ->needs(Filter::class)
    ->give(function (Application $app) {
          return [
              $app->make(NullFilter::class),
              $app->make(ProfanityFilter::class),
              $app->make(TooLongFilter::class),
          ];
    });

もっと手軽に、コンテナに作らせたいクラス名の配列を渡すこともできます。

php
$this->app->when(Firewall::class)
    ->needs(Filter::class)
    ->give([
        NullFilter::class,
        ProfanityFilter::class,
        TooLongFilter::class,
    ]);

タグ付きの可変長引数#

クラスが、Report ...$reports のように、あるクラスの可変長引数を持つこともあります。needs と giveTagged を使うと、そのタグが付いた登録を、まとめて渡せます。

php
$this->app->when(ReportAggregator::class)
    ->needs(Report::class)
    ->giveTagged('reports');

タグ付け#

同じ種類の登録を、まとめて取り出したいときがあります。たとえば、レポートを分析するクラスが、Report インターフェースのいろいろな実装を配列で受け取るとします。実装を登録したあとで、tag メソッドで同じタグを付けておきます。

php
$this->app->bind(CpuReport::class, function () {
    // ...
});

$this->app->bind(MemoryReport::class, function () {
    // ...
});

$this->app->tag([CpuReport::class, MemoryReport::class], 'reports');

タグを付けたら、コンテナの tagged メソッドで、まとめて取り出せます。

php
$this->app->bind(ReportAnalyzer::class, function (Application $app) {
    return new ReportAnalyzer($app->tagged('reports'));
});

登録したものを包む(extend)#

extend を使うと、コンテナが作ったサービスに手を加えられます。たとえば、サービスが作られたときに、機能を足したり(別のクラスで包んだり)、設定を足したりする処理を動かせます。引数は2つです。包みたいサービスのクラスと、手を加えたサービスを返すクロージャです。クロージャは、作られたサービスとコンテナを受け取ります。

php
$this->app->extend(Service::class, function (Service $service, Application $app) {
    return new DecoratedService($service);
});

取り出す(リゾルブ)#

make メソッド#

コンテナから取り出すことを「リゾルブ(解決)」といいます。make メソッドで、コンテナからクラスのインスタンスを取り出せます。取り出したいクラスかインターフェースの名前を渡します。

php
use App\Services\Transistor;

$transistor = $this->app->make(Transistor::class);

クラスが必要とする道具の中に、コンテナが作れないものがあるときは、makeWith に連想配列(名前と値の組の並び)で渡せます。たとえば、Transistor のコンストラクタの引数 $id を、自分で渡せます。

php
use App\Services\Transistor;

$transistor = $this->app->makeWith(Transistor::class, ['id' => 1]);

bound は、そのクラスやインターフェースが、コンテナに登録されている(自分で登録した)かを調べます。

php
if ($this->app->bound(Transistor::class)) {
    // ...
}

サービスプロバイダの外で、$app が使えない場所なら、App ファサードか、app ヘルパー関数で取り出せます。

php
use App\Services\Transistor;
use Illuminate\Support\Facades\App;

$transistor = App::make(Transistor::class);

$transistor = app(Transistor::class);

コンテナが作るクラスに、コンテナ自身を渡したいときは、コンストラクタに Illuminate\Container\Container の型を書きます。

php
use Illuminate\Container\Container;

/**
 * Create a new class instance.
 */
public function __construct(
    protected Container $container,
) {}

自動の注入#

もう1つ、とても大切な方法があります。コンテナが作るクラスのコンストラクタに、必要な道具の型を書いておく方法です。コントローラー・イベントのリスナー・ミドルウェアなどが、コンテナが作るクラスです。また、キューのジョブの handle メソッドにも型を書けます。ふだん使うオブジェクトのほとんどは、この方法でコンテナから受け取るのがふつうです。

たとえば、コントローラーのコンストラクタに、アプリのサービスの型を書くと、自動で作られて渡されます。

php
<?php

namespace App\Http\Controllers;

use App\Services\AppleMusic;

class PodcastController extends Controller
{
    /**
     * Create a new controller instance.
     */
    public function __construct(
        protected AppleMusic $apple,
    ) {}

    /**
     * Show information about the given podcast.
     */
    public function show(string $id): Podcast
    {
        return $this->apple->findPodcast($id);
    }
}

取り出すメソッドのまとめ#

メソッド 説明
make クラスやインターフェースを取り出す
makeWith コンテナが作れない引数を、連想配列で渡して取り出す
bound 登録されているかを調べる
App::make App ファサードで取り出す
app() ヘルパー関数で取り出す

メソッドを呼ぶときの注入#

オブジェクトのメソッドを呼ぶときに、そのメソッドが必要とする道具も、コンテナに自動で渡してほしいことがあります。たとえば、次のクラスです。

php
<?php

namespace App;

use App\Services\AppleMusic;

class PodcastStats
{
    /**
     * Generate a new podcast stats report.
     */
    public function generate(AppleMusic $apple): array
    {
        return [
            // ...
        ];
    }
}

generate メソッドは、コンテナ経由で、次のように呼べます。

php
use App\PodcastStats;
use Illuminate\Support\Facades\App;

$stats = App::call([new PodcastStats, 'generate']);

call メソッドには、PHP で呼べるもの(関数・メソッド・クロージャなど)なら何でも渡せます。クロージャを呼んで、そのクロージャが必要とする道具を自動で渡すこともできます。

php
use App\Services\AppleMusic;
use Illuminate\Support\Facades\App;

$result = App::call(function (AppleMusic $apple) {
    // ...
});

コンテナのイベント#

サービスコンテナは、オブジェクトを作るたびに、イベント(「〜が起きた」という知らせ)を出します。resolving メソッドで、このイベントを受け取れます。

php
use App\Services\Transistor;
use Illuminate\Contracts\Foundation\Application;

$this->app->resolving(Transistor::class, function (Transistor $transistor, Application $app) {
    // コンテナが「Transistor」型のオブジェクトを作ったときに呼ばれる...
});

$this->app->resolving(function (mixed $object, Application $app) {
    // コンテナがどんな型のオブジェクトを作ったときでも呼ばれる...
});

作られたオブジェクトが、コールバック(あとで呼ばれる関数)に渡されます。使う側に渡る前に、オブジェクトにプロパティ(クラスの中の変数)を足して設定できます。

登録しなおしたとき(rebinding)#

rebinding を使うと、サービスがコンテナに登録しなおされたときに知らせを受け取れます。登録しなおすとは、最初の登録のあとで、もう一度登録したり上書きしたりすることです。登録が変わるたびに、使う道具を入れかえたり、動きを変えたりしたいときに役立ちます。

php
use App\Contracts\PodcastPublisher;
use App\Services\SpotifyPublisher;
use App\Services\TransistorPublisher;
use Illuminate\Contracts\Foundation\Application;

$this->app->bind(PodcastPublisher::class, SpotifyPublisher::class);

$this->app->rebinding(
    PodcastPublisher::class,
    function (Application $app, PodcastPublisher $newInstance) {
        //
    },
);

// 新しい登録で、rebinding のクロージャが呼ばれる...
$this->app->bind(PodcastPublisher::class, TransistorPublisher::class);

PSR-11#

Laravel のサービスコンテナは、PSR-11(PHP のコンテナの共通の決まり)のインターフェースを実装しています。そのため、PSR-11 のコンテナの型を書けば、Laravel のコンテナが渡されます。

php
use App\Services\Transistor;
use Psr\Container\ContainerInterface;

Route::get('/', function (ContainerInterface $container) {
    $service = $container->get(Transistor::class);

    // ...
});

渡した名前のものを取り出せないときは、例外(エラーの知らせ)が投げられます。名前が一度も登録されていなければ、Psr\Container\NotFoundExceptionInterface の例外です。登録はあるのに作れなかったときは、Psr\Container\ContainerExceptionInterface の例外です。

関連するページ#

公式ドキュメント(英語)

2026年10月5日時点の内容をもとに、日本語でまとめています。

ページの一覧