Service Container

Introduction

The Laravel service container is a powerful tool for managing class dependencies. Dependency injection is a fancy word that essentially means this: class dependencies are "injected" into the class via the constructor or, in some cases, "setter" methods.

In this example, the PurchasePodcast command handler needs to send e-mails when a podcast is purchased. So, we will inject a service that is able to send e-mails. Since the service is injected, we are able to easily swap it out with another implementation. We are also able to easily "mock", or create a dummy implementation of the mailer 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.

Basic Usage

Binding

Almost all of your service container bindings will be registered within service providers, so all of these examples will demonstrate using the container in that context. However, if you need an instance of the container elsewhere in your application, such as a factory, you may type-hint the Illuminate\Contracts\Container\Container contract and an instance of the container will be injected for you. Alternatively, you may use the App facade to access the container.

Registering A Basic Resolver

Within a service provider, you always have access to the container via the $this->app instance variable.

There are several ways the service container can register dependencies, including Closure callbacks and binding interfaces to implementations. First, we'll explore Closure callbacks. A Closure resolver is registered in the container with a key (typically the class name) and a Closure that returns some value:

Resolving

There are several ways to resolve something out of the container. First, you may use the make method:

$fooBar = $this->app->make('FooBar');

Secondly, you may use "array access" on the container, since it implements PHP's ArrayAccess interface:

$fooBar = $this->app['FooBar'];

Lastly, but most importantly, you may simply "type-hint" the dependency in the constructor of a class that is resolved by the container, including controllers, event listeners, queue jobs, filters, and more. The container will automatically inject the dependencies:

Binding Interfaces To Implementations

Injecting Concrete Dependencies

A very powerful features of the service container is its ability to bind an interface to a given implementation. For example, perhaps our application integrates with the Pusher web service for sending and receiving real-time events. If we are using Pusher's PHP SDK, we could inject an instance of the Pusher client into a class:

In this example, it is good that we are injecting the class dependencies; however, we are tightly coupled to the Pusher SDK. If the Pusher SDK methods change or we decide to switch to a new event service entirely, we will need to change our CreateOrderHandler code.

Program To An Interface

In order to "insulate" the CreateOrderHandler against changes to event pushing, we could define an EventPusher interface and a PusherEventPusher implementation:

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, when our system receives a new Order, we may want to send an event via PubNub rather than Pusher. Laravel provides a simple, fluent interface for definining this behavior:

Tagging

Occasionally, you may need to resolve all of a certain "category" of binding. For example, perhaps you are building a report aggregator 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:

Practical Applications

Laravel provides several opportunities to use the service container to increase the flexibility and testability of your application. One primary example is when resolving controllers. All controllers are resolved through the service container, meaning you can type-hint dependencies in a controller constructor, and they will automatically be injected.

In this example, the OrderRepository class will automatically be injected into the controller. This means that a "mock" OrderRepository may be bound into the container when unit testing, allowing for painless stubbing of database layer interaction.

Other Examples Of Container Usage

Of course, as mentioned above, controllers are not the only classes Laravel resolves via the service container. You may also type-hint dependencies on route Closures, filters, queue jobs, event listeners, and more. For examples of using the service container in these contexts, please refer to their documentation.

Container Events

Registering A Resolving Listener

The container fires an event each time it resolves an object. You may listen to this event using the resolving method: