서비스 컨테이너
업데이트됨번역일: 2026년 8월 2일
이 페이지는 원문이 업데이트되어 번역이 갱신되었습니다.
- 원문 수정
- 2026년 8월 2일
- 번역 갱신
- 2026년 8월 2일
서비스 컨테이너
소개
Laravel 서비스 컨테이너는 클래스 의존성을 관리하고 의존성 주입(Dependency Injection)을 수행하는 강력한 도구입니다. 의존성 주입이란, 클래스가 필요로 하는 의존 객체를 생성자 또는 경우에 따라 setter 메서드를 통해 "주입"받는 방식을 말합니다.
간단한 예를 살펴보겠습니다.
<?php
namespace App\Http\Controllers;
use App\Services\AppleMusic;
use Illuminate\View\View;
class PodcastController extends Controller
{
/**
* 새 컨트롤러 인스턴스 생성
*/
public function __construct(
protected AppleMusic $apple,
) {}
/**
* 특정 팟캐스트 정보를 표시
*/
public function show(string $id): View
{
return view('podcasts.show', [
'podcast' => $this->apple->findPodcast($id)
]);
}
}이 예제에서 PodcastController는 Apple Music 같은 외부 소스에서 팟캐스트 데이터를 가져와야 합니다. 이를 위해 팟캐스트를 조회할 수 있는 서비스를 주입받습니다. 서비스가 주입되는 구조이므로, 테스트 시 AppleMusic 서비스를 가짜 구현체(mock)로 손쉽게 교체할 수 있습니다.
규모가 크고 견고한 애플리케이션을 만들거나 Laravel 코어에 기여하려면 서비스 컨테이너를 깊이 이해하는 것이 필수입니다.
설정 없는 자동 해결
클래스에 의존성이 없거나, 인터페이스가 아닌 구체 클래스에만 의존하는 경우 컨테이너에 별도 설정 없이도 자동으로 해결됩니다. 예를 들어 routes/web.php에 다음과 같이 작성할 수 있습니다.
<?php
class Service
{
// ...
}
Route::get('/', function (Service $service) {
dd($service::class);
});/ 라우트에 접근하면 컨테이너가 Service 클래스를 자동으로 해결하여 라우트 핸들러에 주입합니다. 복잡한 설정 파일 없이도 의존성 주입의 이점을 누릴 수 있다는 점이 핵심입니다.
컨트롤러, 이벤트 리스너, 미들웨어 등 Laravel 애플리케이션을 구성하는 많은 클래스들이 컨테이너를 통해 의존성을 자동으로 받습니다. 큐 Job의 handle 메서드에서도 타입힌트로 의존성을 주입받을 수 있습니다. 한 번 자동 의존성 주입에 익숙해지면 없이는 개발하기 어려울 정도로 편리합니다.
컨테이너를 직접 사용해야 할 때
설정 없는 자동 해결 덕분에, 대부분의 경우 컨테이너를 직접 다루지 않아도 라우트, 컨트롤러, 이벤트 리스너 등에서 타입힌트만으로 의존성을 주입받을 수 있습니다. 예를 들어 라우트 정의에서 Illuminate\Http\Request를 타입힌트하면, 컨테이너가 뒤에서 알아서 주입을 처리합니다.
use Illuminate\Http\Request;
Route::get('/', function (Request $request) {
// ...
});자동 의존성 주입과 파사드 덕분에 컨테이너를 직접 다룰 일이 거의 없습니다. 그렇다면 언제 컨테이너를 직접 사용해야 할까요?
두 가지 상황이 있습니다. 첫째, 인터페이스를 구현하는 클래스를 작성하고 라우트나 생성자에서 해당 인터페이스를 타입힌트로 사용하려면 컨테이너에 인터페이스와 구현체를 연결해야 합니다. 둘째, 다른 Laravel 개발자와 공유할 패키지를 개발하는 경우 패키지의 서비스를 컨테이너에 바인딩해야 할 수 있습니다.
바인딩
바인딩 기본
단순 바인딩
대부분의 바인딩은 서비스 프로바이더 안에서 등록합니다. 아래 예제들도 서비스 프로바이더의 맥락에서 작성된 것입니다.
서비스 프로바이더 내에서는 $this->app 프로퍼티로 컨테이너에 접근할 수 있습니다. bind 메서드를 사용해 등록할 클래스나 인터페이스 이름과, 인스턴스를 반환하는 클로저를 전달하면 됩니다.
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));
});NOTE
인터페이스에 의존하지 않는 클래스는 컨테이너에 별도로 바인딩할 필요가 없습니다. 리플렉션을 통해 자동으로 해결할 수 있기 때문입니다.
싱글턴 바인딩
singleton 메서드는 클래스나 인터페이스를 한 번만 해결되도록 바인딩합니다. 싱글턴으로 등록된 바인딩은 이후 컨테이너에서 요청될 때마다 동일한 인스턴스가 반환됩니다.
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
namespace App\Services;
use Illuminate\Container\Attributes\Singleton;
#[Singleton]
class Transistor
{
// ...
}스코프 싱글턴 바인딩
scoped 메서드는 하나의 Laravel 요청(request) 또는 Job 라이프사이클 안에서 한 번만 해결되도록 바인딩합니다. singleton과 유사하지만, Laravel Octane 워커가 새 요청을 처리하거나 큐 워커가 새 Job을 처리할 때처럼 새 라이프사이클이 시작되면 인스턴스가 초기화됩니다.
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] 어트리뷰트를 붙여 요청/Job 라이프사이클 내에서 한 번만 해결되도록 지정할 수도 있습니다.
<?php
namespace App\Services;
use Illuminate\Container\Attributes\Scoped;
#[Scoped]
class Transistor
{
// ...
}인스턴스 바인딩
이미 생성된 객체 인스턴스를 instance 메서드로 컨테이너에 등록할 수 있습니다. 이후 컨테이너에서 해당 타입을 요청하면 항상 같은 인스턴스가 반환됩니다.
use App\Services\Transistor;
use App\Services\PodcastParser;
$service = new Transistor(new PodcastParser);
$this->app->instance(Transistor::class, $service);인터페이스와 구현체 바인딩
서비스 컨테이너의 강력한 기능 중 하나는 인터페이스를 특정 구현체에 바인딩하는 것입니다. 예를 들어 EventPusher 인터페이스와 RedisEventPusher 구현체가 있다면, 다음과 같이 등록합니다.
use App\Contracts\EventPusher;
use App\Services\RedisEventPusher;
$this->app->bind(EventPusher::class, RedisEventPusher::class);이렇게 하면 어떤 클래스가 EventPusher를 필요로 할 때 컨테이너가 RedisEventPusher를 주입합니다. 이후 구현체를 교체해야 할 때는 바인딩만 변경하면 됩니다. 컨트롤러, 이벤트 리스너, 미들웨어 등 컨테이너를 통해 해결되는 모든 클래스에서 인터페이스를 타입힌트로 사용할 수 있습니다.
use App\Contracts\EventPusher;
/**
* 새 클래스 인스턴스 생성
*/
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] 어트리뷰트와 함께 사용해 해결 범위를 지정할 수도 있습니다.
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
{
// ...
}NOTE
BindWhen 어트리뷰트를 사용하려면 PHP 8.5 이상이 필요합니다.
컨텍스트 바인딩
같은 인터페이스를 사용하지만 클래스마다 다른 구현체를 주입해야 할 때 컨텍스트 바인딩을 사용합니다. 예를 들어 두 컨트롤러가 Illuminate\Contracts\Filesystem\Filesystem 컨트랙트를 사용하되 각각 다른 스토리지 드라이버를 필요로 한다면 다음과 같이 설정합니다.
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,
) {
// ...
}
}#[RouteParameter]는 변수 이름과 일치하는 라우트 파라미터를 해결합니다. 명시적으로 파라미터 이름을 지정하려면 #[RouteParameter('photo')]처럼 작성하세요.
#[RequestAttribute]는 현재 요청의 어트리뷰트 백에서 해당 키에 저장된 값을 해결합니다.
현재 인증된 사용자를 주입하려면 #[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
{
/**
* 새 어트리뷰트 인스턴스 생성
*/
public function __construct(public string $key, public mixed $default = null)
{
}
/**
* 설정 값 해결
*
* @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);
}
}기본값 바인딩
클래스가 다른 클래스뿐 아니라 정수 같은 기본값(primitive)도 주입받아야 할 때, 컨텍스트 바인딩을 통해 쉽게 처리할 수 있습니다.
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');타입 지정 가변 인자 바인딩
가변 인자(variadic)로 타입이 지정된 객체 배열을 받는 클래스가 있을 수 있습니다.
<?php
use App\Models\Filter;
use App\Services\Logger;
class Firewall
{
/**
* 필터 인스턴스 목록
*
* @var array
*/
protected $filters;
/**
* 새 클래스 인스턴스 생성
*/
public function __construct(
protected Logger $logger,
Filter ...$filters,
) {
$this->filters = $filters;
}
}컨텍스트 바인딩을 통해 해결된 Filter 인스턴스 배열을 반환하는 클로저를 give 메서드에 전달할 수 있습니다.
$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 인터페이스 구현체 배열을 받는 리포트 분석기를 만든다고 가정해 보겠습니다. 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 메서드는 확장할 서비스 클래스와, 수정된 서비스를 반환하는 클로저를 인자로 받습니다. 클로저는 해결된 서비스와 컨테이너 인스턴스를 받습니다.
$this->app->extend(Service::class, function (Service $service, Application $app) {
return new DecoratedService($service);
});해결(Resolving)
`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;
/**
* 새 클래스 인스턴스 생성
*/
public function __construct(
protected Container $container,
) {}자동 주입
실제로 가장 많이 사용하는 방식은 생성자에서 타입힌트를 통해 의존성을 자동으로 주입받는 것입니다. 컨트롤러, 이벤트 리스너, 미들웨어, 큐 Job의 handle 메서드 등에서 모두 활용할 수 있습니다.
예를 들어 컨트롤러 생성자에서 서비스를 타입힌트하면, 컨테이너가 자동으로 해결하여 주입해 줍니다.
<?php
namespace App\Http\Controllers;
use App\Services\AppleMusic;
class PodcastController extends Controller
{
/**
* 새 컨트롤러 인스턴스 생성
*/
public function __construct(
protected AppleMusic $apple,
) {}
/**
* 특정 팟캐스트 정보를 반환
*/
public function show(string $id): Podcast
{
return $this->apple->findPodcast($id);
}
}메서드 호출과 주입
객체 인스턴스의 특정 메서드를 호출할 때, 컨테이너가 해당 메서드의 의존성을 자동으로 주입하도록 할 수 있습니다. 예를 들어 다음과 같은 클래스가 있다고 가정합니다.
<?php
namespace App;
use App\Services\AppleMusic;
class PodcastStats
{
/**
* 팟캐스트 통계 리포트 생성
*/
public function generate(AppleMusic $apple): array
{
return [
// ...
];
}
}컨테이너의 call 메서드를 통해 generate를 호출하면 의존성이 자동으로 주입됩니다.
use App\PodcastStats;
use Illuminate\Support\Facades\App;
$stats = App::call([new PodcastStats, 'generate']);call 메서드는 PHP callable이면 무엇이든 받을 수 있습니다. 클로저도 마찬가지로 의존성을 자동 주입받습니다.
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 메서드는 서비스가 컨테이너에 다시 바인딩될 때(즉, 기존 바인딩이 재등록되거나 교체될 때) 이를 감지할 수 있게 해줍니다. 특정 바인딩이 변경될 때마다 의존성을 업데이트하거나 동작을 수정해야 할 때 유용합니다.
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 인터페이스를 구현합니다. 따라서 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의 인스턴스가 던져집니다.