conteneur de service
- Liaison de base
- Liaison simple
- Lier un singleton
- Lier une instance
- Liaison étendue
- Instance d'analyse
- méthode make
- injecte automatiquement
- événements de conteneur
- PSR -11
- Introduction au conteneur de service
- Resolve
- Méthode Make
- Injecter automatiquement
- Événements de conteneur
- PSR-11
- Introduction
- Le conteneur de services Laravel est un outil puissant pour gérer les dépendances de classe et effectuer l'injection de dépendances. Le terme sophistiqué d'injection de dépendances signifie essentiellement que les dépendances d'une classe sont "injectées" dans la classe via le constructeur ou, dans certains cas, la méthode "setter".
- Regardons un exemple simple :
<?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]); } }
Dans cet exemple, le contrôleur - Si vous souhaitez créer des applications puissantes à grande échelle, une chose est cruciale : une compréhension approfondie du conteneur de services Laravel. Bien sûr, il en va de même pour la contribution au code principal de Laravel.
UserController
doit extraire les utilisateurs de la source de données. Par conséquent, nous devons injecter un service qui puisse attirer les utilisateurs. Dans le contexte actuel, notreUserRepository
utilise très probablement Eloquent pour obtenir des informations utilisateur à partir de la base de données. Cependant, puisque le référentiel est injecté, nous pouvons facilement le basculer vers une autre implémentation. La commodité de cette méthode d'injection est que lorsque nous écrivons des tests pour notre application, nous pouvons également facilement « nous moquer » ou créer une implémentation virtuelle deUserRepository
. - Regardons un exemple simple :
- Liaison de service
Liaison de base
Étant donné que les conteneurs de services de la plupart des utilisateurs sont enregistrés auprès d'un service fournisseur, donc la plupart des exemples ci-dessous démontrent l’utilisation de conteneurs au sein d’un fournisseur de services. {tip} Si un conteneur ne dépend d'aucune interface, il n'est pas nécessaire de lier des classes dans ce conteneur. Le conteneur n'a pas besoin de spécifier comment construire ces objets car il peut utiliser la réflexion pour résoudre automatiquement ces objets.
- Extended Binding
Liaison simple
Chez un fournisseur de services, vous pouvez toujours accéder au conteneur via l'attribut $this->app
. Nous pouvons enregistrer la liaison via la méthode bind
du conteneur. Le premier paramètre de la méthode bind
est le nom de la classe/interface à lier, et le deuxième paramètre est un retour. class. Exemple de Closure
: $this->app->bind('HelpSpot\API', function ($app) {
return new HelpSpot\API($app->make('HttpClient'));
});
Notez que nous acceptons le conteneur lui-même comme paramètre de l'analyseur. Nous pouvons ensuite utiliser le conteneur pour résoudre les sous-dépendances de l'objet en cours de construction.
Lier un singleton
La méthode singleton
lie une classe ou une interface à un conteneur qui n'est résolu qu'une seule fois. Une fois la liaison singleton résolue, la même instance d'objet est renvoyée au conteneur lors des appels suivants :
$this->app->singleton('HelpSpot\API', function ($app) { return new HelpSpot\API($app->make('HttpClient')); });
Instances de liaison
Vous pouvez également lier une instance d'objet existante à un conteneur à l'aide de la méthode instance
. L'instance donnée sera toujours renvoyée au conteneur lors des appels suivants : instance
方法将现有对象实例绑定到容器中。给定的实例会始终在随后的调用中返回到容器中:
$api = new HelpSpot\API(new HttpClient); $this->app->instance('HelpSpot\API', $api);
绑定基本值
当你有一个类不仅需要接受一个注入类,还需要注入一个基本值(比如整数)。你可以使用上下文绑定来轻松注入你的类需要的任何值:
$this->app->when('App\Http\Controllers\UserController') ->needs('$variableName') ->give($value);
绑定接口到实现
服务容器有一个很强大的功能,就是支持绑定接口到给定的实现。例如,如果我们有个 EventPusher
接口 和一个 RedisEventPusher
实现。一旦我们写完了 EventPusher
接口的 RedisEventPusher
实现,我们就可以在服务容器中注册它,像这样:
$this->app->bind( 'App\Contracts\EventPusher', 'App\Services\RedisEventPusher' );
这么做相当于告诉容器:当一个类需要实现 EventPusher
时,应该注入 RedisEventPusher
。现在我们就可以在构造函数或者任何其他通过服务容器注入依赖项的地方使用类型提示注入 EventPusher
接口:
use App\Contracts\EventPusher; /** * Create a new class instance. * * @param EventPusher $pusher * @return void */ public function __construct(EventPusher $pusher){ $this->pusher = $pusher; }
上下文绑定
有时你可能有两个类使用了相同的接口,但你希望各自注入不同的实现。例如, 有两个控制器可能依赖了 IlluminateContractsFilesystemFilesystem
契约. Laravel 提供了一个简单的,优雅的接口来定义这个行为:
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'); });
标记
有时候,你可能需要解析某个 “分类” 下的所有绑定。 比如, 你可能正在构建一个报表的聚合器,它接收一个包含不同 Report
接口实现的数组。注册 Report
实现之后,你可以使用 tag
方法给他们分配一个标签:
$this->app->bind('SpeedReport', function () { // }); $this->app->bind('MemoryReport', function () { // }); $this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');
一旦服务被标记,你就可以通过 tagged
方法轻松地解析它们:
$this->app->bind('ReportAggregator', function ($app) { return new ReportAggregator($app->tagged('reports')); });
扩展绑定
extend
方法可以修改已解析的服务。比如,当一个服务被解析后,你可以添加额外的代码来修饰或者配置它。 extend
方法接受一个闭包,该闭包唯一的参数就是这个服务, 并返回修改过的服务:
$this->app->extend(Service::class, function ($service) { return new DecoratedService($service); });
解析实例
make
方法
你可以使用 make
方法从容器中解析出类实例。 make
方法接收你想要解析的类或接口的名字:
$api = $this->app->make('HelpSpot\API');
如果你的代码处于无法访问 $app
变量的位置,则可用全局辅助函数 resolve
来解析:
$api = resolve('HelpSpot\API');
如果类依赖不能通过容器解析,你可以通过将它们作为关联数组作为 makeWith
$api = $this->app->makeWith('HelpSpot\API', ['id' => 1]);Liaison d'une valeur de base
<?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) { // } }🎜🎜
Liaison d'interfaces aux implémentations
🎜Service Une fonctionnalité très puissante des conteneurs est qu'ils prennent en charge les interfaces de liaison à une implémentation donnée. Par exemple, si nous avons une interfaceEventPusher
et une implémentation RedisEventPusher
. Une fois que nous avons écrit l'implémentation RedisEventPusher
de l'interface EventPusher
, nous pouvons l'enregistrer dans le conteneur de services, comme ceci : 🎜$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"... });🎜Cela équivaut à dire au conteneur : quand une classe Lorsque vous devez implémenter
EventPusher
, vous devez injecter RedisEventPusher
. Nous pouvons maintenant utiliser des astuces de type pour injecter l'interface EventPusher
dans le constructeur ou à tout autre endroit où les dépendances sont injectées via le conteneur de service : 🎜use Psr\Container\ContainerInterface; Route::get('/', function (ContainerInterface $container) { $service = $container->get('Service'); // });🎜🎜🎜< h3> Liaison de contexte🎜Parfois, vous pouvez avoir deux classes qui utilisent la même interface, mais vous souhaitez injecter des implémentations différentes dans chacune. Par exemple, deux contrôleurs peuvent s'appuyer sur le contrat
IlluminateContractsFilesystemFilesystem
Laravel fournit une interface simple et élégante pour définir ce comportement : 🎜rrreee🎜🎜🎜Mark🎜Parfois, vous devrez peut-être analyser toutes les liaisons dans une certaine "catégorie". Par exemple, vous pourriez créer un agrégateur de rapports qui reçoit un tableau de différentes implémentations de l'interface Report
. Après avoir enregistré les implémentations de Report
, vous pouvez leur attribuer une balise en utilisant la méthode tag
: 🎜rrreee🎜Une fois le service balisé, vous pouvez l'attribuer via tagged< /code> Méthodes pour les analyser facilement : 🎜rrreee🎜🎜🎜Extending Bindings
🎜Les méthodes extend
peuvent modifier les services résolus. Par exemple, une fois un service résolu, vous pouvez ajouter du code supplémentaire pour le décorer ou le configurer. La méthode extend
accepte une fermeture dont le seul paramètre est le service, et renvoie le service modifié : 🎜rrreee🎜🎜🎜Instance de résolution< /h2>🎜< une méthode name="the-make-method">🎜🎜🎜make
🎜🎜Vous pouvez utiliser la méthode make
pour résoudre une instance de classe à partir d'un conteneur. La méthode make
reçoit le nom de la classe ou de l'interface que vous souhaitez résoudre : 🎜rrreee🎜Si votre code est dans une position où vous ne pouvez pas accéder à la variable $app
, vous peut utiliser la fonction d'assistance globale< code>resolve
pour résoudre : 🎜rrreee🎜Si les dépendances de classe ne peuvent pas être résolues par le conteneur, vous pouvez les injecter sous forme de tableau associatif en tant que paramètre de makeWith
méthode : 🎜rrreee🎜🎜🎜🎜Injection automatique
Extending Bindings
🎜Les méthodesextend
peuvent modifier les services résolus. Par exemple, une fois un service résolu, vous pouvez ajouter du code supplémentaire pour le décorer ou le configurer. La méthode extend
accepte une fermeture dont le seul paramètre est le service, et renvoie le service modifié : 🎜rrreee🎜🎜🎜Instance de résolution< /h2>🎜< une méthode name="the-make-method">🎜🎜🎜make
🎜🎜Vous pouvez utiliser la méthode make
pour résoudre une instance de classe à partir d'un conteneur. La méthode make
reçoit le nom de la classe ou de l'interface que vous souhaitez résoudre : 🎜rrreee🎜Si votre code est dans une position où vous ne pouvez pas accéder à la variable $app
, vous peut utiliser la fonction d'assistance globale< code>resolve
De plus, et plus important encore, vous pouvez simplement utiliser des "indices de type" pour injecter des dépendances qui doivent être résolues par le conteneur dans le constructeur de la classe, y compris les contrôleurs, les écouteurs d'événements, les tâches de file d'attente, le middleware, etc. . En fait, c’est ainsi que la plupart des objets doivent être résolus par le conteneur.
Par exemple, vous pouvez ajouter un indice de type de référentiel dans le constructeur du contrôleur, puis le référentiel sera automatiquement analysé et injecté dans la classe :
rrreeeÉvénements du conteneur
Chaque fois que le conteneur de service analyse l'objet déclenchera un événement, vous pouvez utiliser la méthode resolving
pour écouter cet événement : resolving
方法监听这个事件 :
正如你所看到的,被解析的对象将会被传入回调函数,这使得你能够在对象被传给调用者之前给它设置额外的属性。
PSR-11
Laravel 的服务容器实现了 PSR-11 接口。因此,你可以使用 PSR-11 容器 『接口类型提示』 来获取 Laravel 容器的实例:
rrreee如果无法解析给定的标识符,则将会引发异常。未绑定标识符时,会抛出 PsrContainerNotFoundExceptionInterface
异常。如果标识符已绑定但无法解析,会抛出 PsrContainerContainerExceptionInterface
rrreee
PsrContainerNotFoundExceptionInterface
est levée. Si l'identifiant est lié mais ne peut pas être résolu, une exception PsrContainerContainerExceptionInterface
est levée. 🎜🎜Cet article a été publié pour la première fois sur le site 🎜LearnKu.com🎜. 🎜🎜