Files
laravelDocScrappy/output/12.x/container.md
2025-09-02 15:19:23 +02:00

1818 lines
43 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Service Container
* Introduction
* Zero Configuration Resolution
* When to Utilize the Container
* Binding
* Binding Basics
* Binding Interfaces to Implementations
* Contextual Binding
* Contextual Attributes
* Binding Primitives
* Binding Typed Variadics
* Tagging
* Extending Bindings
* Resolving
* The Make Method
* Automatic Injection
* Method Invocation and Injection
* Container Events
* Rebinding
* PSR-11
## Introduction
The Laravel service container is a powerful tool for managing class
dependencies and performing dependency injection. Dependency injection is a
fancy phrase that essentially means this: class dependencies are "injected"
into the class via the constructor or, in some cases, "setter" methods.
Let's look at a simple example:
1<?php
2 
3namespace App\Http\Controllers;
4 
5use App\Services\AppleMusic;
6use Illuminate\View\View;
7 
8class PodcastController extends Controller
9{
10 /**
11 * Create a new controller instance.
12 */
13 public function __construct(
14 protected AppleMusic $apple,
15 ) {}
16 
17 /**
18 * Show information about the given podcast.
19 */
20 public function show(string $id): View
21 {
22 return view('podcasts.show', [
23 'podcast' => $this->apple->findPodcast($id)
24 ]);
25 }
26}
<?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)
]);
}
}
In this example, the `PodcastController` needs to retrieve podcasts from a
data source such as Apple Music. So, we will **inject** a service that is able
to retrieve podcasts. Since the service is injected, we are able to easily
"mock", or create a dummy implementation of the `AppleMusic` service when
testing our application.
A deep understanding of the Laravel service container is essential to building
a powerful, large application, as well as for contributing to the Laravel core
itself.
### Zero Configuration Resolution
If a class has no dependencies or only depends on other concrete classes (not
interfaces), the container does not need to be instructed on how to resolve
that class. For example, you may place the following code in your
`routes/web.php` file:
1<?php
2 
3class Service
4{
5 // ...
6}
7 
8Route::get('/', function (Service $service) {
9 dd($service::class);
10});
<?php
class Service
{
// ...
}
Route::get('/', function (Service $service) {
dd($service::class);
});
In this example, hitting your application's `/` route will automatically
resolve the `Service` class and inject it into your route's handler. This is
game changing. It means you can develop your application and take advantage of
dependency injection without worrying about bloated configuration files.
Thankfully, many of the classes you will be writing when building a Laravel
application automatically receive their dependencies via the container,
including [controllers](/docs/12.x/controllers), [event
listeners](/docs/12.x/events), [middleware](/docs/12.x/middleware), and more.
Additionally, you may type-hint dependencies in the `handle` method of [queued
jobs](/docs/12.x/queues). Once you taste the power of automatic and zero
configuration dependency injection it feels impossible to develop without it.
### When to Utilize the Container
Thanks to zero configuration resolution, you will often type-hint dependencies
on routes, controllers, event listeners, and elsewhere without ever manually
interacting with the container. For example, you might type-hint the
`Illuminate\Http\Request` object on your route definition so that you can
easily access the current request. Even though we never have to interact with
the container to write this code, it is managing the injection of these
dependencies behind the scenes:
1use Illuminate\Http\Request;
2 
3Route::get('/', function (Request $request) {
4 // ...
5});
use Illuminate\Http\Request;
Route::get('/', function (Request $request) {
// ...
});
In many cases, thanks to automatic dependency injection and
[facades](/docs/12.x/facades), you can build Laravel applications without
**ever** manually binding or resolving anything from the container. **So, when
would you ever manually interact with the container?** Let's examine two
situations.
First, if you write a class that implements an interface and you wish to type-
hint that interface on a route or class constructor, you must tell the
container how to resolve that interface. Secondly, if you are [writing a
Laravel package](/docs/12.x/packages) that you plan to share with other
Laravel developers, you may need to bind your package's services into the
container.
## Binding
### Binding Basics
#### Simple Bindings
Almost all of your service container bindings will be registered within
[service providers](/docs/12.x/providers), so most of these examples will
demonstrate using the container in that context.
Within a service provider, you always have access to the container via the
`$this->app` property. We can register a binding using the `bind` method,
passing the class or interface name that we wish to register along with a
closure that returns an instance of the class:
1use App\Services\Transistor;
2use App\Services\PodcastParser;
3use Illuminate\Contracts\Foundation\Application;
4 
5$this->app->bind(Transistor::class, function (Application $app) {
6 return new Transistor($app->make(PodcastParser::class));
7});
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));
});
Note that we receive the container itself as an argument to the resolver. We
can then use the container to resolve sub-dependencies of the object we are
building.
As mentioned, you will typically be interacting with the container within
service providers; however, if you would like to interact with the container
outside of a service provider, you may do so via the `App`
[facade](/docs/12.x/facades):
1use App\Services\Transistor;
2use Illuminate\Contracts\Foundation\Application;
3use Illuminate\Support\Facades\App;
4 
5App::bind(Transistor::class, function (Application $app) {
6 // ...
7});
use App\Services\Transistor;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\App;
App::bind(Transistor::class, function (Application $app) {
// ...
});
You may use the `bindIf` method to register a container binding only if a
binding has not already been registered for the given type:
1$this->app->bindIf(Transistor::class, function (Application $app) {
2 return new Transistor($app->make(PodcastParser::class));
3});
$this->app->bindIf(Transistor::class, function (Application $app) {
return new Transistor($app->make(PodcastParser::class));
});
For convenience, you may omit providing the class or interface name that you
wish to register as a separate argument and instead allow Laravel to infer the
type from the return type of the closure you provide to the `bind` method:
1App::bind(function (Application $app): Transistor {
2 return new Transistor($app->make(PodcastParser::class));
3});
App::bind(function (Application $app): Transistor {
return new Transistor($app->make(PodcastParser::class));
});
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.
#### Binding A Singleton
The `singleton` method binds a class or interface into the container that
should only be resolved one time. Once a singleton binding is resolved, the
same object instance will be returned on subsequent calls into the container:
1use App\Services\Transistor;
2use App\Services\PodcastParser;
3use Illuminate\Contracts\Foundation\Application;
4 
5$this->app->singleton(Transistor::class, function (Application $app) {
6 return new Transistor($app->make(PodcastParser::class));
7});
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));
});
You may use the `singletonIf` method to register a singleton container binding
only if a binding has not already been registered for the given type:
1$this->app->singletonIf(Transistor::class, function (Application $app) {
2 return new Transistor($app->make(PodcastParser::class));
3});
$this->app->singletonIf(Transistor::class, function (Application $app) {
return new Transistor($app->make(PodcastParser::class));
});
#### Singleton Attribute
Alternatively, you may mark an interface or class with the `#[Singleton]`
attribute to indicate to the container that it should be resolved one time:
1<?php
2 
3namespace App\Services;
4 
5use Illuminate\Container\Attributes\Singleton;
6 
7#[Singleton]
8class Transistor
9{
10 // ...
11}
<?php
namespace App\Services;
use Illuminate\Container\Attributes\Singleton;
#[Singleton]
class Transistor
{
// ...
}
#### Binding Scoped Singletons
The `scoped` method binds a class or interface into the container that should
only be resolved one time within a given Laravel request / job lifecycle.
While this method is similar to the `singleton` method, instances registered
using the `scoped` method will be flushed whenever the Laravel application
starts a new "lifecycle", such as when a [Laravel Octane](/docs/12.x/octane)
worker processes a new request or when a Laravel [queue
worker](/docs/12.x/queues) processes a new job:
1use App\Services\Transistor;
2use App\Services\PodcastParser;
3use Illuminate\Contracts\Foundation\Application;
4 
5$this->app->scoped(Transistor::class, function (Application $app) {
6 return new Transistor($app->make(PodcastParser::class));
7});
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));
});
You may use the `scopedIf` method to register a scoped container binding only
if a binding has not already been registered for the given type:
1$this->app->scopedIf(Transistor::class, function (Application $app) {
2 return new Transistor($app->make(PodcastParser::class));
3});
$this->app->scopedIf(Transistor::class, function (Application $app) {
return new Transistor($app->make(PodcastParser::class));
});
#### Scoped Attribute
Alternatively, you may mark an interface or class with the `#[Scoped]`
attribute to indicate to the container that it should be resolved one time
within a given Laravel request / job lifecycle:
1<?php
2 
3namespace App\Services;
4 
5use Illuminate\Container\Attributes\Scoped;
6 
7#[Scoped]
8class Transistor
9{
10 // ...
11}
<?php
namespace App\Services;
use Illuminate\Container\Attributes\Scoped;
#[Scoped]
class Transistor
{
// ...
}
#### Binding Instances
You may also bind an existing object instance into the container using the
`instance` method. The given instance will always be returned on subsequent
calls into the container:
1use App\Services\Transistor;
2use App\Services\PodcastParser;
3 
4$service = new Transistor(new PodcastParser);
5 
6$this->app->instance(Transistor::class, $service);
use App\Services\Transistor;
use App\Services\PodcastParser;
$service = new Transistor(new PodcastParser);
$this->app->instance(Transistor::class, $service);
### Binding Interfaces to Implementations
A very powerful feature of the service container is its ability to bind an
interface to a given implementation. For example, let's assume we have an
`EventPusher` interface and a `RedisEventPusher` implementation. Once we have
coded our `RedisEventPusher` implementation of this interface, we can register
it with the service container like so:
1use App\Contracts\EventPusher;
2use App\Services\RedisEventPusher;
3 
4$this->app->bind(EventPusher::class, RedisEventPusher::class);
use App\Contracts\EventPusher;
use App\Services\RedisEventPusher;
$this->app->bind(EventPusher::class, RedisEventPusher::class);
This statement tells the container that it should inject the
`RedisEventPusher` when a class needs an implementation of `EventPusher`. Now
we can type-hint the `EventPusher` interface in the constructor of a class
that is resolved by the container. Remember, controllers, event listeners,
middleware, and various other types of classes within Laravel applications are
always resolved using the container:
1use App\Contracts\EventPusher;
2 
3/**
4 * Create a new class instance.
5 */
6public function __construct(
7 protected EventPusher $pusher,
8) {}
use App\Contracts\EventPusher;
/**
* Create a new class instance.
*/
public function __construct(
protected EventPusher $pusher,
) {}
#### Bind Attribute
Laravel also provides a `Bind` attribute for added convenience. You can apply
this attribute to any interface to tell Laravel which implementation should be
automatically injected whenever that interface is requested. When using the
`Bind` attribute, there is no need to perform any additional service
registration in your application's service providers.
In addition, multiple `Bind` attributes may be placed on an interface in order
to configure a different implementation that should be injected for a given
set of environments:
1<?php
2 
3namespace App\Contracts;
4 
5use App\Services\FakeEventPusher;
6use App\Services\RedisEventPusher;
7use Illuminate\Container\Attributes\Bind;
8 
9#[Bind(RedisEventPusher::class)]
10#[Bind(FakeEventPusher::class, environments: ['local', 'testing'])]
11interface EventPusher
12{
13 // ...
14}
<?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
{
// ...
}
Furthermore, Singleton and Scoped attributes may be applied to indicate if the
container bindings should be resolved once or once per request / job
lifecycle:
1use App\Services\RedisEventPusher;
2use Illuminate\Container\Attributes\Bind;
3use Illuminate\Container\Attributes\Singleton;
4 
5#[Bind(RedisEventPusher::class)]
6#[Singleton]
7interface EventPusher
8{
9 // ...
10}
use App\Services\RedisEventPusher;
use Illuminate\Container\Attributes\Bind;
use Illuminate\Container\Attributes\Singleton;
#[Bind(RedisEventPusher::class)]
#[Singleton]
interface EventPusher
{
// ...
}
### Contextual Binding
Sometimes you may have two classes that utilize the same interface, but you
wish to inject different implementations into each class. For example, two
controllers may depend on different implementations of the
`Illuminate\Contracts\Filesystem\Filesystem` [contract](/docs/12.x/contracts).
Laravel provides a simple, fluent interface for defining this behavior:
1use App\Http\Controllers\PhotoController;
2use App\Http\Controllers\UploadController;
3use App\Http\Controllers\VideoController;
4use Illuminate\Contracts\Filesystem\Filesystem;
5use Illuminate\Support\Facades\Storage;
6 
7$this->app->when(PhotoController::class)
8 ->needs(Filesystem::class)
9 ->give(function () {
10 return Storage::disk('local');
11 });
12 
13$this->app->when([VideoController::class, UploadController::class])
14 ->needs(Filesystem::class)
15 ->give(function () {
16 return Storage::disk('s3');
17 });
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');
});
### Contextual Attributes
Since contextual binding is often used to inject implementations of drivers or
configuration values, Laravel offers a variety of contextual binding
attributes that allow to inject these types of values without manually
defining the contextual bindings in your service providers.
For example, the `Storage` attribute may be used to inject a specific [storage
disk](/docs/12.x/filesystem):
1<?php
2 
3namespace App\Http\Controllers;
4 
5use Illuminate\Container\Attributes\Storage;
6use Illuminate\Contracts\Filesystem\Filesystem;
7 
8class PhotoController extends Controller
9{
10 public function __construct(
11 #[Storage('local')] protected Filesystem $filesystem
12 ) {
13 // ...
14 }
15}
<?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
) {
// ...
}
}
In addition to the `Storage` attribute, Laravel offers `Auth`, `Cache`,
`Config`, `Context`, `DB`, `Give`, `Log`, `RouteParameter`, and Tag
attributes:
1<?php
2 
3namespace App\Http\Controllers;
4 
5use App\Contracts\UserRepository;
6use App\Models\Photo;
7use App\Repositories\DatabaseRepository;
8use Illuminate\Container\Attributes\Auth;
9use Illuminate\Container\Attributes\Cache;
10use Illuminate\Container\Attributes\Config;
11use Illuminate\Container\Attributes\Context;
12use Illuminate\Container\Attributes\DB;
13use Illuminate\Container\Attributes\Give;
14use Illuminate\Container\Attributes\Log;
15use Illuminate\Container\Attributes\RouteParameter;
16use Illuminate\Container\Attributes\Tag;
17use Illuminate\Contracts\Auth\Guard;
18use Illuminate\Contracts\Cache\Repository;
19use Illuminate\Database\Connection;
20use Psr\Log\LoggerInterface;
21 
22class PhotoController extends Controller
23{
24 public function __construct(
25 #[Auth('web')] protected Guard $auth,
26 #[Cache('redis')] protected Repository $cache,
27 #[Config('app.timezone')] protected string $timezone,
28 #[Context('uuid')] protected string $uuid,
29 #[Context('ulid', hidden: true)] protected string $ulid,
30 #[DB('mysql')] protected Connection $connection,
31 #[Give(DatabaseRepository::class)] protected UserRepository $users,
32 #[Log('daily')] protected LoggerInterface $log,
33 #[RouteParameter('photo')] protected Photo $photo,
34 #[Tag('reports')] protected iterable $reports,
35 ) {
36 // ...
37 }
38}
<?php
namespace App\Http\Controllers;
use App\Contracts\UserRepository;
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\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,
#[RouteParameter('photo')] protected Photo $photo,
#[Tag('reports')] protected iterable $reports,
) {
// ...
}
}
Furthermore, Laravel provides a `CurrentUser` attribute for injecting the
currently authenticated user into a given route or class:
1use App\Models\User;
2use Illuminate\Container\Attributes\CurrentUser;
3 
4Route::get('/user', function (#[CurrentUser] User $user) {
5 return $user;
6})->middleware('auth');
use App\Models\User;
use Illuminate\Container\Attributes\CurrentUser;
Route::get('/user', function (#[CurrentUser] User $user) {
return $user;
})->middleware('auth');
#### Defining Custom Attributes
You can create your own contextual attributes by implementing the
`Illuminate\Contracts\Container\ContextualAttribute` contract. The container
will call your attribute's `resolve` method, which should resolve the value
that should be injected into the class utilizing the attribute. In the example
below, we will re-implement Laravel's built-in `Config` attribute:
1<?php
2 
3namespace App\Attributes;
4 
5use Attribute;
6use Illuminate\Contracts\Container\Container;
7use Illuminate\Contracts\Container\ContextualAttribute;
8 
9#[Attribute(Attribute::TARGET_PARAMETER)]
10class Config implements ContextualAttribute
11{
12 /**
13 * Create a new attribute instance.
14 */
15 public function __construct(public string $key, public mixed $default = null)
16 {
17 }
18 
19 /**
20 * Resolve the configuration value.
21 *
22 * @param self $attribute
23 * @param \Illuminate\Contracts\Container\Container $container
24 * @return mixed
25 */
26 public static function resolve(self $attribute, Container $container)
27 {
28 return $container->make('config')->get($attribute->key, $attribute->default);
29 }
30}
<?php
namespace App\Attributes;
use Attribute;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Container\ContextualAttribute;
#[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
* @return mixed
*/
public static function resolve(self $attribute, Container $container)
{
return $container->make('config')->get($attribute->key, $attribute->default);
}
}
### Binding Primitives
Sometimes you may have a class that receives some injected classes, but also
needs an injected primitive value such as an integer. You may easily use
contextual binding to inject any value your class may need:
1use App\Http\Controllers\UserController;
2 
3$this->app->when(UserController::class)
4 ->needs('$variableName')
5 ->give($value);
use App\Http\Controllers\UserController;
$this->app->when(UserController::class)
->needs('$variableName')
->give($value);
Sometimes a class may depend on an array of tagged instances. Using the
`giveTagged` method, you may easily inject all of the container bindings with
that tag:
1$this->app->when(ReportAggregator::class)
2 ->needs('$reports')
3 ->giveTagged('reports');
$this->app->when(ReportAggregator::class)
->needs('$reports')
->giveTagged('reports');
If you need to inject a value from one of your application's configuration
files, you may use the `giveConfig` method:
1$this->app->when(ReportAggregator::class)
2 ->needs('$timezone')
3 ->giveConfig('app.timezone');
$this->app->when(ReportAggregator::class)
->needs('$timezone')
->giveConfig('app.timezone');
### Binding Typed Variadics
Occasionally, you may have a class that receives an array of typed objects
using a variadic constructor argument:
1<?php
2 
3use App\Models\Filter;
4use App\Services\Logger;
5 
6class Firewall
7{
8 /**
9 * The filter instances.
10 *
11 * @var array
12 */
13 protected $filters;
14 
15 /**
16 * Create a new class instance.
17 */
18 public function __construct(
19 protected Logger $logger,
20 Filter ...$filters,
21 ) {
22 $this->filters = $filters;
23 }
24}
<?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;
}
}
Using contextual binding, you may resolve this dependency by providing the
`give` method with a closure that returns an array of resolved `Filter`
instances:
1$this->app->when(Firewall::class)
2 ->needs(Filter::class)
3 ->give(function (Application $app) {
4 return [
5 $app->make(NullFilter::class),
6 $app->make(ProfanityFilter::class),
7 $app->make(TooLongFilter::class),
8 ];
9 });
$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),
];
});
For convenience, you may also just provide an array of class names to be
resolved by the container whenever `Firewall` needs `Filter` instances:
1$this->app->when(Firewall::class)
2 ->needs(Filter::class)
3 ->give([
4 NullFilter::class,
5 ProfanityFilter::class,
6 TooLongFilter::class,
7 ]);
$this->app->when(Firewall::class)
->needs(Filter::class)
->give([
NullFilter::class,
ProfanityFilter::class,
TooLongFilter::class,
]);
#### Variadic Tag Dependencies
Sometimes a class may have a variadic dependency that is type-hinted as a
given class (`Report ...$reports`). Using the `needs` and `giveTagged`
methods, you may easily inject all of the container bindings with that tag for
the given dependency:
1$this->app->when(ReportAggregator::class)
2 ->needs(Report::class)
3 ->giveTagged('reports');
$this->app->when(ReportAggregator::class)
->needs(Report::class)
->giveTagged('reports');
### Tagging
Occasionally, you may need to resolve all of a certain "category" of binding.
For example, perhaps you are building a report analyzer that receives an array
of many different `Report` interface implementations. After registering the
`Report` implementations, you can assign them a tag using the `tag` method:
1$this->app->bind(CpuReport::class, function () {
2 // ...
3});
4 
5$this->app->bind(MemoryReport::class, function () {
6 // ...
7});
8 
9$this->app->tag([CpuReport::class, MemoryReport::class], 'reports');
$this->app->bind(CpuReport::class, function () {
// ...
});
$this->app->bind(MemoryReport::class, function () {
// ...
});
$this->app->tag([CpuReport::class, MemoryReport::class], 'reports');
Once the services have been tagged, you may easily resolve them all via the
container's `tagged` method:
1$this->app->bind(ReportAnalyzer::class, function (Application $app) {
2 return new ReportAnalyzer($app->tagged('reports'));
3});
$this->app->bind(ReportAnalyzer::class, function (Application $app) {
return new ReportAnalyzer($app->tagged('reports'));
});
### Extending Bindings
The `extend` method allows the modification of resolved services. For example,
when a service is resolved, you may run additional code to decorate or
configure the service. The `extend` method accepts two arguments, the service
class you're extending and a closure that should return the modified service.
The closure receives the service being resolved and the container instance:
1$this->app->extend(Service::class, function (Service $service, Application $app) {
2 return new DecoratedService($service);
3});
$this->app->extend(Service::class, function (Service $service, Application $app) {
return new DecoratedService($service);
});
## Resolving
### The `make` Method
You may use the `make` method to resolve a class instance from the container.
The `make` method accepts the name of the class or interface you wish to
resolve:
1use App\Services\Transistor;
2 
3$transistor = $this->app->make(Transistor::class);
use App\Services\Transistor;
$transistor = $this->app->make(Transistor::class);
If some of your class's dependencies are not resolvable via the container, you
may inject them by passing them as an associative array into the `makeWith`
method. For example, we may manually pass the `$id` constructor argument
required by the `Transistor` service:
1use App\Services\Transistor;
2 
3$transistor = $this->app->makeWith(Transistor::class, ['id' => 1]);
use App\Services\Transistor;
$transistor = $this->app->makeWith(Transistor::class, ['id' => 1]);
The `bound` method may be used to determine if a class or interface has been
explicitly bound in the container:
1if ($this->app->bound(Transistor::class)) {
2 // ...
3}
if ($this->app->bound(Transistor::class)) {
// ...
}
If you are outside of a service provider in a location of your code that does
not have access to the `$app` variable, you may use the `App`
[facade](/docs/12.x/facades) or the `app` [helper](/docs/12.x/helpers#method-
app) to resolve a class instance from the container:
1use App\Services\Transistor;
2use Illuminate\Support\Facades\App;
3 
4$transistor = App::make(Transistor::class);
5 
6$transistor = app(Transistor::class);
use App\Services\Transistor;
use Illuminate\Support\Facades\App;
$transistor = App::make(Transistor::class);
$transistor = app(Transistor::class);
If you would like to have the Laravel container instance itself injected into
a class that is being resolved by the container, you may type-hint the
`Illuminate\Container\Container` class on your class's constructor:
1use Illuminate\Container\Container;
2 
3/**
4 * Create a new class instance.
5 */
6public function __construct(
7 protected Container $container,
8) {}
use Illuminate\Container\Container;
/**
* Create a new class instance.
*/
public function __construct(
protected Container $container,
) {}
### Automatic Injection
Alternatively, and importantly, you may type-hint the dependency in the
constructor of a class that is resolved by the container, including
[controllers](/docs/12.x/controllers), [event listeners](/docs/12.x/events),
[middleware](/docs/12.x/middleware), and more. Additionally, you may type-hint
dependencies in the `handle` method of [queued jobs](/docs/12.x/queues). In
practice, this is how most of your objects should be resolved by the
container.
For example, you may type-hint a service defined by your application in a
controller's constructor. The service will automatically be resolved and
injected into the class:
1<?php
2 
3namespace App\Http\Controllers;
4 
5use App\Services\AppleMusic;
6 
7class PodcastController extends Controller
8{
9 /**
10 * Create a new controller instance.
11 */
12 public function __construct(
13 protected AppleMusic $apple,
14 ) {}
15 
16 /**
17 * Show information about the given podcast.
18 */
19 public function show(string $id): Podcast
20 {
21 return $this->apple->findPodcast($id);
22 }
23}
<?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);
}
}
## Method Invocation and Injection
Sometimes you may wish to invoke a method on an object instance while allowing
the container to automatically inject that method's dependencies. For example,
given the following class:
1<?php
2 
3namespace App;
4 
5use App\Services\AppleMusic;
6 
7class PodcastStats
8{
9 /**
10 * Generate a new podcast stats report.
11 */
12 public function generate(AppleMusic $apple): array
13 {
14 return [
15 // ...
16 ];
17 }
18}
<?php
namespace App;
use App\Services\AppleMusic;
class PodcastStats
{
/**
* Generate a new podcast stats report.
*/
public function generate(AppleMusic $apple): array
{
return [
// ...
];
}
}
You may invoke the `generate` method via the container like so:
1use App\PodcastStats;
2use Illuminate\Support\Facades\App;
3 
4$stats = App::call([new PodcastStats, 'generate']);
use App\PodcastStats;
use Illuminate\Support\Facades\App;
$stats = App::call([new PodcastStats, 'generate']);
The `call` method accepts any PHP callable. The container's `call` method may
even be used to invoke a closure while automatically injecting its
dependencies:
1use App\Services\AppleMusic;
2use Illuminate\Support\Facades\App;
3 
4$result = App::call(function (AppleMusic $apple) {
5 // ...
6});
use App\Services\AppleMusic;
use Illuminate\Support\Facades\App;
$result = App::call(function (AppleMusic $apple) {
// ...
});
## Container Events
The service container fires an event each time it resolves an object. You may
listen to this event using the `resolving` method:
1use App\Services\Transistor;
2use Illuminate\Contracts\Foundation\Application;
3 
4$this->app->resolving(Transistor::class, function (Transistor $transistor, Application $app) {
5 // Called when container resolves objects of type "Transistor"...
6});
7 
8$this->app->resolving(function (mixed $object, Application $app) {
9 // Called when container resolves object of any type...
10});
use App\Services\Transistor;
use Illuminate\Contracts\Foundation\Application;
$this->app->resolving(Transistor::class, function (Transistor $transistor, Application $app) {
// Called when container resolves objects of type "Transistor"...
});
$this->app->resolving(function (mixed $object, Application $app) {
// Called when container resolves object of any type...
});
As you can see, the object being resolved will be passed to the callback,
allowing you to set any additional properties on the object before it is given
to its consumer.
### Rebinding
The `rebinding` method allows you to listen for when a service is re-bound to
the container, meaning it is registered again or overridden after its initial
binding. This can be useful when you need to update dependencies or modify
behavior each time a specific binding is updated:
1use App\Contracts\PodcastPublisher;
2use App\Services\SpotifyPublisher;
3use App\Services\TransistorPublisher;
4use Illuminate\Contracts\Foundation\Application;
5 
6$this->app->bind(PodcastPublisher::class, SpotifyPublisher::class);
7 
8$this->app->rebinding(
9 PodcastPublisher::class,
10 function (Application $app, PodcastPublisher $newInstance) {
11 //
12 },
13);
14 
15// New binding will trigger rebinding closure...
16$this->app->bind(PodcastPublisher::class, TransistorPublisher::class);
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) {
//
},
);
// New binding will trigger rebinding closure...
$this->app->bind(PodcastPublisher::class, TransistorPublisher::class);
## PSR-11
Laravel's service container implements the [PSR-11](https://github.com/php-
fig/fig-standards/blob/master/accepted/PSR-11-container.md) interface.
Therefore, you may type-hint the PSR-11 container interface to obtain an
instance of the Laravel container:
1use App\Services\Transistor;
2use Psr\Container\ContainerInterface;
3 
4Route::get('/', function (ContainerInterface $container) {
5 $service = $container->get(Transistor::class);
6 
7 // ...
8});
use App\Services\Transistor;
use Psr\Container\ContainerInterface;
Route::get('/', function (ContainerInterface $container) {
$service = $container->get(Transistor::class);
// ...
});
An exception is thrown if the given identifier can't be resolved. The
exception will be an instance of `Psr\Container\NotFoundExceptionInterface` if
the identifier was never bound. If the identifier was bound but was unable to
be resolved, an instance of `Psr\Container\ContainerExceptionInterface` will
be thrown.