Le terme injection de dépendances Laravel est un terme proposé par Martin Fowler. Il s'agit d'un comportement d'injection de composants dans une application. L'injection de dépendances est un élément clé de l'architecture agile. Des exemples d'utilisation sont tels que "class UserProvider{protected $connection. .}".
L'environnement d'exploitation de cet article : système Windows 7, Laravel version 5.7, ordinateur DELL G3.
Qu'est-ce que l'injection de dépendances Laravel ?
Explication détaillée de l'injection de dépendances et de l'IoC dans Laravel :
En tant que développeurs, nous essayons toujours de trouver de nouvelles façons en utilisant des modèles de conception et en essayant de nouveaux frameworks robustes. Écrire bien conçu et un code robuste. Dans cet article, nous explorerons le modèle de conception d'injection de dépendances avec les composants IoC de Laravel et verrons comment il peut améliorer nos conceptions.
Le terme injection de dépendances est un terme proposé par Martin Fowler. Il s'agit de l'acte d'injecter des composants dans une application. Comme l'a dit Ward Cunningham :
L'injection de dépendances est un élément clé de l'architecture agile.
Voyons un exemple :
class UserProvider{ protected $connection; public function __construct(){ $this->connection = new Connection; } public function retrieveByCredentials( array $credentials ){ $user = $this->connection ->where( 'email', $credentials['email']) ->where( 'password', $credentials['password']) ->first(); return $user; } }
Si vous souhaitez tester ou maintenir cette classe, vous devez accéder à l'instance de la base de données pour effectuer certaines requêtes. Pour éviter d'avoir à faire cela, vous pouvez découpler cette classe des autres classes, vous avez l'une des trois options pour injecter la classe Connection
sans l'utiliser directement. Connection
类注入而不需要直接使用它。
将组件注入类时,可以使用以下三个选项之一:
class UserProvider{ protected $connection; public function __construct( Connection $con ){ $this->connection = $con; } ...
同样,我们也可以使用 Setter 方法注入依赖关系:
class UserProvider{ protected $connection; public function __construct(){ ... } public function setConnection( Connection $con ){ $this->connection = $con; } ...
interface ConnectionInjector{ public function injectConnection( Connection $con ); } class UserProvider implements ConnectionInjector{ protected $connection; public function __construct(){ ... } public function injectConnection( Connection $con ){ $this->connection = $con; } }
当一个类实现了我们的接口时,我们定义了 injectConnection
方法来解决依赖关系。
现在,当测试我们的类时,我们可以模拟依赖类并将其作为参数传递。每个类必须专注于一个特定的任务,而不应该关心解决它们的依赖性。这样,你将拥有一个更专注和可维护的应用程序。
如果你想了解更多关于 DI 的信息,Alejandro Gervassio 在 本系列 文章中对其进行了广泛而专业的介绍,所以一定要去读这些文章。那么,什么又是 IoC 呢?IoC (控制反转)不需要使用依赖注入,但它可以帮助你有效的管理依赖关系。
Ioc 是一个简单的组件,可以更加方便地解析依赖项。你可以将对象形容为容器,并且每次解析类时,都会自动注入依赖项。
当你请求一个对象时, Laravel Ioc 在解决依赖关系的方式上有些特殊:
我们使用一个简单的例子,将在本文中改进它。SimpleAuth
类依赖于 FileSessionStorage
,所以我们的代码可能是这样的:
class FileSessionStorage{ public function __construct(){ session_start(); } public function get( $key ){ return $_SESSION[$key]; } public function set( $key, $value ){ $_SESSION[$key] = $value; } } class SimpleAuth{ protected $session; public function __construct(){ $this->session = new FileSessionStorage; } } //创建一个 SimpleAuth $auth = new SimpleAuth();
这是一种经典的方法,让我们从使用构造函数注入开始。
class SimpleAuth{ protected $session; public function __construct( FileSessionStorage $session ){ $this->session = $session; } }
现在我们创建一个对象:
$auth = new SimpleAuth( new FileSessionStorage() );
现在我想使用 Laravel Ioc 来管理这一切。
因为 Application
类继承自 Container
类,所以你可以通过 App
门面来访问容器。
App::bind( 'FileSessionStorage', function(){ return new FileSessionStorage; });
bind
方法第一个参数是要绑定到容器的唯一 ID ,第二个参数是一个回调函数每当执行 FileSessionStorage
类时执行,我们还可以传递一个表示类名的字符串,如下所示。
Note: 如果你查看 Laravel 包时,你将看到绑定有时会分组,比如( view
, view.finder
……)。
假设我们将会话存储转换为 Mysql 存储,我们的类应该类似于:
class MysqlSessionStorage{ public function __construct(){ //... } public function get($key){ // do something } public function set( $key, $value ){ // do something } }
现在我们已经更改了依赖项,我们还需要更改 SimpleAuth
构造函数,并将新对象绑定到容器中!
高级模块不应该依赖于低级模块,两者都应该依赖于抽象对象。
抽象不应该依赖于细节,细节应该取决于抽象。Robert C. Martin
我们的 SimpleAuth
类不应该关心我们的存储是如何完成的,相反它更应该关注于消费的服务。
因此,我们可以抽象实现我们的存储:
interface SessionStorage{ public function get( $key ); public function set( $key, $value ); }
这样我们就可以实现并请求 SessionStorage
class FileSessionStorage implements SessionStorage{ public function __construct(){ //... } public function get( $key ){ //... } public function set( $key, $value ){ //... } } class MysqlSessionStorage implements SessionStorage{ public function __construct(){ //... } public function get( $key ){ //... } public function set( $key, $value ){ //... } } class SimpleAuth{ protected $session; public function __construct( SessionStorage $session ){ $this->session = $session; } }
Uncaught exception 'Illuminate\Container\BindingResolutionException' with message 'Target [SessionStorage] is not instantiable.'
App:bind( 'SessionStorage', 'MysqlSessionStorage' );
injectConnection
pour résoudre les dépendances. 🎜SimpleAuth
dépend de FileSessionStorage
, donc notre code pourrait ressembler à ceci : 🎜rrreee🎜C'est une approche classique, commençons par utiliser le constructeur Infusion commence . 🎜rrreee🎜Maintenant, nous créons un objet : 🎜rrreee🎜Maintenant, je veux utiliser Laravel Ioc pour gérer tout cela. 🎜🎜Étant donné que la classe Application
hérite de la classe Container
, vous pouvez accéder au conteneur via la façade App
. 🎜rrreee🎜Le premier paramètre de la méthode bind
est l'ID unique à lier au conteneur, et le deuxième paramètre est une fonction de rappel qui est exécutée chaque fois que la classe FileSessionStorage
est exécuté. Nous Vous pouvez également transmettre une chaîne représentant le nom de la classe, comme indiqué ci-dessous. 🎜🎜🎜Remarque :🎜 Si vous regardez le package Laravel, vous verrez que les liaisons sont parfois regroupées, comme ( view
, view.finder
...). 🎜🎜 En supposant que nous convertissons le stockage de session en stockage Mysql, notre classe devrait ressembler à : 🎜rrreee🎜 Maintenant que nous avons modifié les dépendances, nous devons également changer le constructeur SimpleAuth
et lier le nouvel objet Set dans un conteneur ! 🎜🎜🎜Les modules de haut niveau ne doivent pas dépendre de modules de bas niveau, les deux doivent dépendre d'objets abstraits. SimpleAuth
ne devrait pas se soucier de la façon dont notre stockage est effectué, mais devrait plutôt se concentrer sur la consommation du service. 🎜🎜Par conséquent, nous pouvons implémenter notre stockage de manière abstraite : 🎜rrreee🎜Afin de pouvoir implémenter et demander une instance de l'interface SessionStorage
: 🎜class FileSessionStorage implements SessionStorage{ public function __construct(){ //... } public function get( $key ){ //... } public function set( $key, $value ){ //... } } class MysqlSessionStorage implements SessionStorage{ public function __construct(){ //... } public function get( $key ){ //... } public function set( $key, $value ){ //... } } class SimpleAuth{ protected $session; public function __construct( SessionStorage $session ){ $this->session = $session; } }
如果我们使用 App::make('SimpleAuth')
通过容器解析 SimpleAuth
类,容器将会抛出 BindingResolutionException
,尝试从绑定解析类之后,返回到反射方法并解析所有依赖项。
Uncaught exception 'Illuminate\Container\BindingResolutionException' with message 'Target [SessionStorage] is not instantiable.'
容器正试图将接口实例化。我们可以为该接口做一个具体的绑定。
App:bind( 'SessionStorage', 'MysqlSessionStorage' );
现在每次我们尝试从容器解析该接口时,我们会得到一个 MysqlSessionStorage
实例。如果我们想要切换我们的存储服务,我们只要变更一下这个绑定。
Note: 如果你想要查看一个类是否已经在容器中被绑定,你可以使用 App::bound('ClassName')
,或者可以使用 App::bindIf('ClassName')
来注册一个还未被注册过的绑定。
Laravel Ioc 也提供 App::singleton('ClassName', 'resolver')
来处理单例的绑定。
你也可以使用 App::instance('ClassName', 'instance')
来创建单例的绑定。
如果容器不能解析依赖项就会抛出 ReflectionException
,但是我们可以使用 App::resolvingAny(Closure)
方法以回调函数的形式来解析任何指定的类型。
Note: 如果你为某个类型已经注册了一个解析方式 resolvingAny
方法仍然会被调用,但它会直接返回 bind
方法的返回值。
这些绑定写在哪儿:
如果只是一个小型应用你可以写在一个全局的起始文件 global/start.php
中,但如果项目变得越来越庞大就有必要使用 Service Provider 。
测试:
当需要快速简易的测试可以考虑使用 php artisan tinker
,它十分强大,且能帮你提升你的 Laravel 测试流程。
Reflection API:
PHP 的 Reflection API 是非常强大的,如果你想要深入 Laravel Ioc 你需要熟悉 Reflection API ,可以先看下这个 教程 来获得更多的信息。
相关推荐:最新的五个Laravel视频教程
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!