Der Begriff „Laravel-Abhängigkeitsinjektion“ ist ein von Martin Fowler vorgeschlagener Begriff. Dabei handelt es sich um ein Schlüsselelement in der agilen Architektur. Anwendungsbeispiele sind „class UserProvider{protected $connection“. . .}".
Die Betriebsumgebung dieses Artikels: Windows 7-System, Laravel Version 5.7, DELL G3-Computer.
Was ist Laravel-Abhängigkeitsinjektion?
Detaillierte Erklärung von Abhängigkeitsinjektion und IoC in Laravel:
Als Entwickler versuchen wir immer, neue Wege zu finden, indem wir Designmuster verwenden und neue robuste Frameworks ausprobieren. Schreiben Sie gut gestaltet und robuster Code. In diesem Artikel untersuchen wir das Dependency-Injection-Designmuster mit den IoC-Komponenten von Laravel und sehen, wie es unsere Designs verbessern kann.
Der Begriff Abhängigkeitsinjektion ist ein von Martin Fowler vorgeschlagener Begriff. Es handelt sich um den Vorgang der Injektion von Komponenten in eine Anwendung. Wie Ward Cunningham sagte:
Abhängigkeitsinjektion ist ein Schlüsselelement in der agilen Architektur.
Sehen wir uns ein Beispiel an:
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; } }
Wenn Sie diese Klasse testen oder warten möchten, müssen Sie auf die Instanz der Datenbank zugreifen, um einige Abfragen durchzuführen. Um dies zu vermeiden, können Sie diese Klasse von anderen Klassen entkoppeln. Sie haben eine von drei Möglichkeiten, die Klasse Connection
einzufügen, ohne sie direkt zu verwenden. 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
, um Abhängigkeiten aufzulösen. 🎜SimpleAuth
hängt von FileSessionStorage
ab, daher könnte unser Code so aussehen: 🎜rrreee🎜Dies ist ein klassischer Ansatz. Beginnen wir mit der Verwendung des Konstruktors Infusion beginnt . 🎜rrreee🎜Jetzt erstellen wir ein Objekt: 🎜rrreee🎜Jetzt möchte ich Laravel Ioc verwenden, um das alles zu verwalten. 🎜🎜Da die Klasse Application
von der Klasse Container
erbt, können Sie über die Fassade App
auf den Container zugreifen. 🎜rrreee🎜Der erste Parameter der Methode bind
ist die eindeutige ID, die an den Container gebunden werden soll, und der zweite Parameter ist eine Rückruffunktion, die immer dann ausgeführt wird, wenn die Klasse FileSessionStorage
ausgeführt wird ausgeführt wird. Sie können auch eine Zeichenfolge übergeben, die den Klassennamen darstellt, wie unten gezeigt. 🎜🎜🎜Hinweis:🎜 Wenn Sie sich das Laravel-Paket ansehen, werden Sie feststellen, dass Bindungen manchmal gruppiert sind, wie zum Beispiel ( view
, view.finder
...). 🎜🎜 Angenommen, wir konvertieren den Sitzungsspeicher in MySQL-Speicher, sollte unsere Klasse wie folgt aussehen: 🎜rrreee🎜 Nachdem wir nun die Abhängigkeiten geändert haben, müssen wir auch den SimpleAuth
-Konstruktor ändern und den neuen Objektsatz binden in einen Behälter! 🎜🎜🎜High-Level-Module sollten nicht von Low-Level-Modulen abhängen, beide sollten von abstrakten Objekten abhängen. SimpleAuth
-Klasse sollte sich nicht darum kümmern, wie unsere Speicherung erfolgt, sondern sich stattdessen auf die Nutzung des Dienstes konzentrieren. 🎜🎜Daher können wir unseren Speicher abstrakt implementieren: 🎜rrreee🎜Damit wir eine Instanz der SessionStorage
-Schnittstelle implementieren und anfordern können: 🎜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视频教程
Das obige ist der detaillierte Inhalt vonWas ist Laravel-Abhängigkeitsinjektion?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!