# 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 $this->apple->findPodcast($id) 24 ]); 25 } 26} $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: 1app` 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: 1app->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: 1app->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: 1app->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): 1middleware('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: 1make('config')->get($attribute->key, $attribute->default); 29 } 30} 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: 1filters = $filters; 23 } 24} 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: 1apple->findPodcast($id); 22 } 23} 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: 1app->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.