サービスコンテナ
クラスが必要とする道具を作って渡してくれるサービスコンテナの考え方と、bind・singleton・属性による登録、取り出し方、PSR-11 の使い方を説明します。
サービスコンテナは、クラスを作って、必要な道具を渡してくれる「道具箱」のようなしくみです。クラスが仕事をするとき、ほかのクラス(道具)を使うことがよくあります。このとき、道具を自分で作らず、外から渡してもらうやり方を「依存性の注入」といいます。難しそうな名前ですが、中身は「コンストラクタ(クラスを作るときに最初に動く部分)や、値を入れるメソッド(セッター)に、必要な道具を渡す」ことです。
まず、簡単な例を見ます。
<?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
class Service
{
// ...
}
Route::get('/', function (Service $service) {
dd($service::class);
});
アプリの / を開くと、Service クラスが自動で作られ、ルートの処理に渡されます。大きな設定ファイルを用意しなくても、依存性の注入が使えるということです。
Laravel のアプリで書くクラスの多くは、コンテナから道具を自動で受け取ります。コントローラー、イベントのリスナー、ミドルウェアなどです。また、キューのジョブの handle メソッドにも、型を書いておくだけで道具を受け取れます。
コンテナをいつ使うのか#
設定なしで作られるので、ふだんはコンテナを意識せずに、ルート・コントローラー・リスナーなどに型を書くだけで道具を受け取れます。たとえば、ルートに Illuminate\Http\Request の型を書けば、いまのリクエストが手に入ります。コンテナを直接さわらなくても、裏ではコンテナが受け渡しをしています。
use Illuminate\Http\Request;
Route::get('/', function (Request $request) {
// ...
});
自動の注入とファサードのおかげで、コンテナへの登録や取り出しを一度も自分でしなくても、Laravel のアプリは作れることが多いです。では、いつコンテナを自分で使うのでしょうか。次の2つの場面があります。
- インターフェース(クラスが守る約束事)を実装したクラスを書き、そのインターフェースの型をルートやコンストラクタに書きたいとき。インターフェースをどのクラスにするかを、コンテナに教える必要があります
- ほかの Laravel の開発者に配るためのパッケージを作るとき。パッケージのサービスを、コンテナに登録する必要があります
登録する(バインディング)#
登録の基本#
コンテナへの登録は、ほとんどがサービスプロバイダ(アプリの起動のときに、道具箱へ道具を登録する場所)の中に書きます。以下の例も、その前提です。
基本の登録(bind)#
サービスプロバイダの中では、いつでも $this->app でコンテナを使えます。登録には bind メソッドを使います。渡すものは2つです。登録したいクラスかインターフェースの名前と、そのインスタンス(クラスから作った実物。オブジェクトともいいます)を作って返すクロージャ(名前のない関数)です。
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 ファサードを使います。
use App\Services\Transistor;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\App;
App::bind(Transistor::class, function (Application $app) {
// ...
});
bindIf は、その型の登録がまだ無いときだけ登録します。
$this->app->bindIf(Transistor::class, function (Application $app) {
return new Transistor($app->make(PodcastParser::class));
});
クラスやインターフェースの名前を別の引数で書かなくても、クロージャの戻り値の型から Laravel が読み取ってくれます。
App::bind(function (Application $app): Transistor {
return new Transistor($app->make(PodcastParser::class));
});
補足
インターフェースに頼らないクラスは、コンテナへ登録する必要がありません。リフレクション(クラスの中身を調べる PHP の機能)で、自動で作れるからです。
シングルトンの登録(singleton)#
singleton は、一度だけ作るクラスやインターフェースを登録します(シングルトンは「1つきり」という意味)。一度作ったあとは、コンテナから何度取り出しても、同じオブジェクトが返ります。
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 は、その型の登録がまだ無いときだけ、シングルトンとして登録します。
$this->app->singletonIf(Transistor::class, function (Application $app) {
return new Transistor($app->make(PodcastParser::class));
});
Singleton 属性#
クラスやインターフェースに #[Singleton] という PHP の属性(クラスやメソッドの前に書く印)を付けても、一度だけ作る指定になります。
<?php
namespace App\Services;
use Illuminate\Container\Attributes\Singleton;
#[Singleton]
class Transistor
{
// ...
}
スコープ付きシングルトンの登録(scoped)#
scoped は、1回のリクエストや1つのジョブを処理するあいだだけ、一度作ったものを使い回す登録です。singleton に似ていますが、Laravel が新しい処理の流れを始めるたびに、作ったものは捨てられます。新しい流れが始まるのは、たとえば Laravel Octane のワーカーが新しいリクエストを扱うときや、キューのワーカーが新しいジョブを扱うときです。
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 は、その型の登録がまだ無いときだけ、スコープ付きとして登録します。
$this->app->scopedIf(Transistor::class, function (Application $app) {
return new Transistor($app->make(PodcastParser::class));
});
Scoped 属性#
#[Scoped] 属性を付けても、1回のリクエスト・ジョブの流れのあいだだけ一度作る指定になります。
<?php
namespace App\Services;
use Illuminate\Container\Attributes\Scoped;
#[Scoped]
class Transistor
{
// ...
}
作ってあるインスタンスの登録(instance)#
自分で作ったオブジェクトを、instance でコンテナに登録できます。そのあとは、取り出すたびに、登録したそのオブジェクトが返ります。
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 があるとします。実装を書いたら、コンテナに次のように登録します。
use App\Contracts\EventPusher;
use App\Services\RedisEventPusher;
$this->app->bind(EventPusher::class, RedisEventPusher::class);
これは、「EventPusher の実装が必要になったら、RedisEventPusher を渡す」という指示です。これで、コンテナが作るクラスなら、コンストラクタに EventPusher の型を書くだけで受け取れます。コントローラー・リスナー・ミドルウェアなどは、いつもコンテナが作っています。
use App\Contracts\EventPusher;
/**
* Create a new class instance.
*/
public function __construct(
protected EventPusher $pusher,
) {}
Bind 属性#
もっと手軽な Bind 属性もあります。インターフェースに付けておくと、そのインターフェースを求められたときに、どの実装を自動で渡すかを決められます。サービスプロバイダに登録を書かなくて済みます。
インターフェースに Bind 属性を複数付けて、環境ごとに別の実装を渡すこともできます。
<?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回のリクエスト・ジョブの流れで一度作る」かを指定できます。
use App\Services\RedisEventPusher;
use Illuminate\Container\Attributes\Bind;
use Illuminate\Container\Attributes\Singleton;
#[Bind(RedisEventPusher::class)]
#[Singleton]
interface EventPusher
{
// ...
}
好きな条件で決めたいときは、BindWhen 属性を使います。条件はクロージャで書きます。クロージャはコンテナを受け取れて、その実装を使うときに true を返すようにします。Bind と BindWhen は、書いた順に調べられます。
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 が用意したインターフェース)の、それぞれ別の実装を使いたい場合です。次のように、メソッドをつないでかんたんに書けます。
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
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
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 属性は、ルートやクラスに、ログインしている利用者を渡します。
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
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);
}
}
数字や文字を渡す(プリミティブの登録)#
クラスといっしょに、整数のような「プリミティブ」(クラスではない、ふつうの値)も受け取りたいことがあります。場面ごとの登録を使えば、どんな値でも渡せます。
use App\Http\Controllers\UserController;
$this->app->when(UserController::class)
->needs('$variableName')
->give($value);
タグ(目印の名前)を付けて登録したものを、配列でまとめて受け取りたいクラスもあります。giveTagged を使うと、そのタグが付いた登録をまとめて渡せます。
$this->app->when(ReportAggregator::class)
->needs('$reports')
->giveTagged('reports');
アプリの設定ファイルの値を渡したいときは、giveConfig を使います。
$this->app->when(ReportAggregator::class)
->needs('$timezone')
->giveConfig('app.timezone');
型付きの可変長引数を渡す#
コンストラクタの可変長引数(個数が決まっていない引数)で、同じ型のオブジェクトの配列を受け取るクラスがあります。
<?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 の配列を返すクロージャを渡します。
$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),
];
});
もっと手軽に、コンテナに作らせたいクラス名の配列を渡すこともできます。
$this->app->when(Firewall::class)
->needs(Filter::class)
->give([
NullFilter::class,
ProfanityFilter::class,
TooLongFilter::class,
]);
タグ付きの可変長引数#
クラスが、Report ...$reports のように、あるクラスの可変長引数を持つこともあります。needs と giveTagged を使うと、そのタグが付いた登録を、まとめて渡せます。
$this->app->when(ReportAggregator::class)
->needs(Report::class)
->giveTagged('reports');
タグ付け#
同じ種類の登録を、まとめて取り出したいときがあります。たとえば、レポートを分析するクラスが、Report インターフェースのいろいろな実装を配列で受け取るとします。実装を登録したあとで、tag メソッドで同じタグを付けておきます。
$this->app->bind(CpuReport::class, function () {
// ...
});
$this->app->bind(MemoryReport::class, function () {
// ...
});
$this->app->tag([CpuReport::class, MemoryReport::class], 'reports');
タグを付けたら、コンテナの tagged メソッドで、まとめて取り出せます。
$this->app->bind(ReportAnalyzer::class, function (Application $app) {
return new ReportAnalyzer($app->tagged('reports'));
});
登録したものを包む(extend)#
extend を使うと、コンテナが作ったサービスに手を加えられます。たとえば、サービスが作られたときに、機能を足したり(別のクラスで包んだり)、設定を足したりする処理を動かせます。引数は2つです。包みたいサービスのクラスと、手を加えたサービスを返すクロージャです。クロージャは、作られたサービスとコンテナを受け取ります。
$this->app->extend(Service::class, function (Service $service, Application $app) {
return new DecoratedService($service);
});
取り出す(リゾルブ)#
make メソッド#
コンテナから取り出すことを「リゾルブ(解決)」といいます。make メソッドで、コンテナからクラスのインスタンスを取り出せます。取り出したいクラスかインターフェースの名前を渡します。
use App\Services\Transistor;
$transistor = $this->app->make(Transistor::class);
クラスが必要とする道具の中に、コンテナが作れないものがあるときは、makeWith に連想配列(名前と値の組の並び)で渡せます。たとえば、Transistor のコンストラクタの引数 $id を、自分で渡せます。
use App\Services\Transistor;
$transistor = $this->app->makeWith(Transistor::class, ['id' => 1]);
bound は、そのクラスやインターフェースが、コンテナに登録されている(自分で登録した)かを調べます。
if ($this->app->bound(Transistor::class)) {
// ...
}
サービスプロバイダの外で、$app が使えない場所なら、App ファサードか、app ヘルパー関数で取り出せます。
use App\Services\Transistor;
use Illuminate\Support\Facades\App;
$transistor = App::make(Transistor::class);
$transistor = app(Transistor::class);
コンテナが作るクラスに、コンテナ自身を渡したいときは、コンストラクタに Illuminate\Container\Container の型を書きます。
use Illuminate\Container\Container;
/**
* Create a new class instance.
*/
public function __construct(
protected Container $container,
) {}
自動の注入#
もう1つ、とても大切な方法があります。コンテナが作るクラスのコンストラクタに、必要な道具の型を書いておく方法です。コントローラー・イベントのリスナー・ミドルウェアなどが、コンテナが作るクラスです。また、キューのジョブの handle メソッドにも型を書けます。ふだん使うオブジェクトのほとんどは、この方法でコンテナから受け取るのがふつうです。
たとえば、コントローラーのコンストラクタに、アプリのサービスの型を書くと、自動で作られて渡されます。
<?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
namespace App;
use App\Services\AppleMusic;
class PodcastStats
{
/**
* Generate a new podcast stats report.
*/
public function generate(AppleMusic $apple): array
{
return [
// ...
];
}
}
generate メソッドは、コンテナ経由で、次のように呼べます。
use App\PodcastStats;
use Illuminate\Support\Facades\App;
$stats = App::call([new PodcastStats, 'generate']);
call メソッドには、PHP で呼べるもの(関数・メソッド・クロージャなど)なら何でも渡せます。クロージャを呼んで、そのクロージャが必要とする道具を自動で渡すこともできます。
use App\Services\AppleMusic;
use Illuminate\Support\Facades\App;
$result = App::call(function (AppleMusic $apple) {
// ...
});
コンテナのイベント#
サービスコンテナは、オブジェクトを作るたびに、イベント(「〜が起きた」という知らせ)を出します。resolving メソッドで、このイベントを受け取れます。
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 を使うと、サービスがコンテナに登録しなおされたときに知らせを受け取れます。登録しなおすとは、最初の登録のあとで、もう一度登録したり上書きしたりすることです。登録が変わるたびに、使う道具を入れかえたり、動きを変えたりしたいときに役立ちます。
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 のコンテナが渡されます。
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日時点の内容をもとに、日本語でまとめています。