The binding basis

Almost all service container binding is done in the service provider.

The directory structure is shown below

Note: There is no need to bind a class to a container if it is not based on any interface. The container doesn’t need to be told how to build objects, because it automatically resolves the concrete objects using PHP’s reflection service.

Simple binding

In a service provider, we can access the container via the $this->app variable, and then register a binding using the bind method, which takes two arguments, the first being the name of the class or interface we want to register, and the second a closure that returns an instance of the class:

 $this->app->bind('HelpSpot\API', function ($app) {
 return new HelpSpot\API($app->make('HttpClient'));
});
Copy the code

Notice that we take the container itself as an argument to the parser, which we can then use to resolve the child dependencies of the object we are building.

Bind a singleton

The Singleton method binds a class or interface to the container that is parsed only once, and subsequent calls to the container return the same object instance:

$this->app->singleton('HelpSpot\API', function ($app) {
 return new HelpSpot\API($app->make('HttpClient'));
});
Copy the code

Bind raw value

You might have a class that receives an injected class and needs to inject a native value such as an integer. You can easily inject any value that the class needs in context:

$this->app->when('App\Http\Controllers\UserController')
 ->needs('$variableName')
 ->give($value);
Copy the code

Bind the interface to the implementation

A very powerful feature of a service container is that it binds interfaces to implementations. We assume we have an EventPusher interface and its implementation class, RedisEventPusher. After writing the RedisEventPusher implementation of the interface, we can register it with the service container:

$this->app->bind(
 'App\Contracts\EventPusher', 
 'App\Services\RedisEventPusher'
);
Copy the code

This code tells the container that RedisEventPusher will be injected when a class needs an implementation of EventPusher. Now we can inject the EventPusher interface dependency in the constructor or any other place where the dependency is injected through the service container:

use App\Contracts\EventPusher; Public function __construct(EventPusher $pusher){public function __construct(EventPusher $pusher){ $this->pusher = $pusher; }Copy the code

Context binding

Sometimes we might have two classes using the same interface, but we want to inject different implementations in each class, for example, two controllers rely on different implementations of the Illuminate\Contracts\Filesystem\Filesystem. Laravel defines a simple, smooth interface for this:

use Illuminate\Support\Facades\Storage;
use App\Http\Controllers\VideoController;
use App\Http\Controllers\PhotoControllers;
use Illuminate\Contracts\Filesystem\Filesystem;

$this->app->when(PhotoController::class)
 ->needs(Filesystem::class)
 ->give(function () {
 return Storage::disk('local');
 });

$this->app->when(VideoController::class)
 ->needs(Filesystem::class)
 ->give(function () {
 return Storage::disk('s3');
 });
Copy the code

The label

In rare cases, we need to resolve all the bindings under a particular classification. For example, if you are building a Report aggregator that accepts multiple different implementations of the Report interface, after registering the Report implementation, you can assign a tag to them using the tag method:

$this->app->bind('SpeedReport', function () {
 //
});

$this->app->bind('MemoryReport', function () {
 //
});

$this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');
Copy the code

Once these services are tagged, they can be easily resolved using the tagged method:

$this->app->bind('ReportAggregator', function ($app) {
 return new ReportAggregator($app->tagged('reports'));
});
Copy the code

The extended binding extend method allows modifications to the parse service. For example, when a service is parsed, you can run additional code to decorate or configure the service. The extend method receives a closure to return the modified service:

$this->app->extend(Service::class, function($service) {
 return new DecoratedService($service);
});
Copy the code