service container
- Basic Binding
- Simple Binding
- Bind a singleton
- Bind instance
- Bind basic value
- Bind interface to implementation
- Context binding
- Marking
- Extended binding
- Parse instance
- make method
- Automatic injection
- Container events
- PSR-11
- Introduction
- Binding
- Parsing
- ##Container events
- PSR-11
Service Container
<?php namespace App\Http\Controllers; use App\User; use App\Repositories\UserRepository; use App\Http\Controllers\Controller; class UserController extends Controller{ /** * 用户存储库的实现. * * @var UserRepository */ protected $users; /** * 创建新的控制器实例. * * @param UserRepository $users * @return void */ public function __construct(UserRepository $users) { $this->users = $users; } /** * 显示指定用户的 profile. * * @param int $id * @return Response */ public function show($id) { $user = $this->users->find($id); return view('user.profile', ['user' => $user]); } }In this example, the controller
UserController needs to get users from the data source. Therefore, we need to
inject a service that can obtain users. In the current context, our UserRepository is most likely using Eloquent to obtain user information from the database. However, since the repository is injected, we can easily switch it to another implementation. The convenience of this injection method is also reflected in that when we write tests for the application, we can also easily "mock" or create a virtual implementation of
UserRepository.
Due to the large Most user service containers are registered with service providers, so most of the examples below demonstrate the use of containers within service providers.
{tip} If a container does not depend on any interface, there is no need to bind classes in this container. The container does not need to specify how to construct these objects because it can use reflection to resolve these objects automatically.Simple binding
In a service provider, you can always access the container through the
$this->app property. We can register binding through the bind
method of the container. The first parameter of the bind
method is the class/interface name to be bound, and the second parameter is a return class instance. Closure
:
Note that we accept the container itself as an argument to the parser. We can then use the container to resolve the sub-dependencies of the object being built. $this->app->bind('HelpSpot\API', function ($app) {
return new HelpSpot\API($app->make('HttpClient'));
});
Bind a singleton
singleton method binds a class or interface to a container that is resolved only once. Once the singleton binding is resolved, the same object instance is returned to the container on subsequent calls: You can also use the When you have a class that not only needs to accept an injected class, but also needs to inject a basic value (such as an integer). You can use context binding to easily inject any value your class needs: The service container has A very powerful feature is support for binding interfaces to given implementations. For example, if we have an Doing so is equivalent to telling the container: when When a class needs to implement Sometimes you may have two classes that use the same interface, but you want to inject different implementations into each. For example, two controllers may depend on the Sometimes, you may need to parse all bindings under a certain "category". For example, you might be building a report aggregator that receives an array of different Once the service is tagged, you can assign it via You can use the If your code is in a position where you cannot access the If class dependencies cannot be resolved by the container, you can inject them by injecting them as associative arrays as arguments to the In addition, and more importantly, you can simply use "type hints" to inject dependencies that need to be resolved by the container in the constructor of the class, including controllers and events. Listeners, queue tasks, middleware, etc. In fact, this is how most objects should be resolved by the container. For example, you can add a repository type hint in the controller's constructor, and then the repository will be automatically parsed and injected into the class: Every time the service container parses an object, an event will be triggered. You can use the As you said As you can see, the parsed object will be passed into the callback function, which allows you to set additional properties on the object before it is passed to the caller. Laravel’s service container implements the PSR-11 interface. Therefore, you can use the PSR-11 container "interface type hint" to obtain an instance of the Laravel container: If the given identifier cannot be resolved, an exception will be thrown. When the identifier is not bound, a $this->app->singleton('HelpSpot\API', function ($app) {
return new HelpSpot\API($app->make('HttpClient'));
});
Bind instance
instance
method to bind an existing object instance to the container. The given instance will always be returned to the container on subsequent calls: $api = new HelpSpot\API(new HttpClient);
$this->app->instance('HelpSpot\API', $api);
Binding basic values
$this->app->when('App\Http\Controllers\UserController')
->needs('$variableName')
->give($value);
Bind the interface to the implementation
EventPusher
interface and a RedisEventPusher
implementation. Once we have written the RedisEventPusher
implementation of the EventPusher
interface, we can register it in the service container, like this: $this->app->bind(
'App\Contracts\EventPusher',
'App\Services\RedisEventPusher'
);
EventPusher
, it should inject RedisEventPusher
. Now we can use type hints to inject the EventPusher
interface in the constructor or anywhere else where dependencies are injected through the service container: use App\Contracts\EventPusher;
/**
* Create a new class instance.
*
* @param EventPusher $pusher
* @return void
*/
public function __construct(EventPusher $pusher){
$this->pusher = $pusher;
}
Context Binding
Illuminate\Contracts\Filesystem\Filesystem
contract. Laravel provides a simple, elegant interface to define this behavior: use Illuminate\Support\Facades\Storage;
use App\Http\Controllers\PhotoController;
use App\Http\Controllers\VideoController;
use Illuminate\Contracts\Filesystem\Filesystem;
$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');
});
Marks
Report
interface implementations. 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');
tagged
Methods to easily parse them: $this->app->bind('ReportAggregator', function ($app) {
return new ReportAggregator($app->tagged('reports'));
});
Extend Bindings
extend
Methods can modify resolved services. For example, after a service is resolved, you can add additional code to decorate or configure it. extend
The method accepts a closure whose only parameter is the service and returns the modified service: $this->app->extend(Service::class, function ($service) {
return new DecoratedService($service);
});
Analysis Example
make
Method make
method to resolve a class from the container Example. The make
method accepts the name of the class or interface you want to resolve: $api = $this->app->make('HelpSpot\API');
$app
variable, you can use the global helper Function resolve
to resolve: $api = resolve('HelpSpot\API');
makeWith
method: $api = $this->app->makeWith('HelpSpot\API', ['id' => 1]);
Automatic injection
<?php
namespace App\Http\Controllers;
use App\Users\Repository as UserRepository;
class UserController extends Controller{
/**
* The user repository instance.
*/
protected $users;
/**
* Create a new controller instance.
*
* @param UserRepository $users
* @return void
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
}
/**
* Show the user with the given ID.
*
* @param int $id
* @return Response
*/
public function show($id)
{
//
}
}
Container events
resolving
method to listen to this event: $this->app->resolving(function ($object, $app) {
// Called when container resolves object of any type...
});
$this->app->resolving(HelpSpot\API::class, function ($api, $app) {
// Called when container resolves objects of type "HelpSpot\API"...
});
PSR-11
use Psr\Container\ContainerInterface;
Route::get('/', function (ContainerInterface $container) {
$service = $container->get('Service');
//
});
Psr\Container\NotFoundExceptionInterface
exception is thrown. If the identifier is bound but cannot be resolved, a Psr\Container\ContainerExceptionInterface
exception is thrown.