依赖注入demo
让我们看一个例子:
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; } }
如果你要测试或者维护这个类,你必须访问数据库的实例来进行一些查询。为了避免必须这样做,你可以将此类与其他类进行 解耦 ,你有三个选项之一,可以将 Connection
类注入而不需要直接使用它。
将组件注入类时,可以使用以下三个选项之一:
构造方法注入
class UserProvider{ protected $connection; public function __construct( Connection $con ){ $this->connection = $con; } }
Setter 方法注入
同样,我们也可以使用 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
方法来解决依赖关系。
优势
现在,当测试我们的类时,我们可以模拟依赖类并将其作为参数传递。每个类必须专注于一个特定的任务,而不应该关心解决它们的依赖性。这样,你将拥有一个更专注和可维护的应用程序。
======================= 华丽的分割线 =================== 目录结构:
部分代码:
index.php
<?php spl_autoload_register('autoLoad', true, true); use a\TestA; use b\TestB; // 要调用的类 $class = TestA::class; // 调用类中的方法 $method = 'hello'; $obj = createObj($class); $methodParam = parseMethod(TestA::class, $method); call_user_func_array([$obj, $method], $methodParam); /** * 根据类名 创建对象 并自动注入 * @param string $className * @return object * @throws ReflectionException */ function createObj(string $className): object { $reflction = new ReflectionClass($className); $paramList = parseConstructor($reflction); $obj = $reflction->newInstanceArgs($paramList); return $obj; } /** * 解析类的构造函数,返回参数列表 * @param ReflectionClass $reflction * @return array */ function parseConstructor(ReflectionClass $reflction): array { $paramList = []; // 如果构造方法存在,返回 object(ReflectionMethod) 反之返回 null $constructor = $reflction->getConstructor(); if (!is_null($constructor)) { // 返回数组 object(ReflectionParameter) 参数列表 $params = $constructor->getParameters(); foreach ($params as $param) { // 获取参数的类型提示类,类型为 object(ReflectionClass) 若没有返回 null if (!is_null($param->getClass())) { // 获取类名 $paramList[] = createObj($param->getClass()->getName()); } else { // 获取默认值 $paramList[] = $param->getDefaultValue(); } } } return $paramList; } /** * 解析返回类的某方法参数 * * @param string $className * @param string $methodName * @return array * @throws ReflectionException */ function parseMethod(string $className, string $methodName) { $paramList = []; // object(ReflectionMethod) $reflection = new ReflectionMethod($className, $methodName); $params = $reflection->getParameters(); foreach ($params as $param) { // 获取参数的类型提示类,类型为 object(ReflectionClass) 若没有返回 null if (!is_null($param->getClass())) { // 获取类名 $paramList[] = createObj($param->getClass()->getName()); } else { // 获取默认值 $paramList[] = $param->getDefaultValue(); } } return $paramList; } function autoLoad($className) { require_once __DIR__.'/'.$className.'.php'; } function dump($data) { echo '<pre>'; var_dump($data); exit(); }
class TestA
<?php namespace a; use b\TestB; use face\Test; class TestA implements Test { const VERSION = 'A'; public $name; public $objB; public function __construct(TestB $b, $name='aaa') { $this->objB = $b; $this->name = $name; } public function hello(TestB $b) { var_dump($b); } }
class TestB
<?php namespace b; use face\Test; use c\TestC; class TestB implements Test { const VERSION = 'B'; public $name; public $objC; public function __construct($name = 'bbb', TestC $c) { $this->objC = $c; $this->name = $name; } }
class TestC
<?php namespace c; use face\Test; class TestC implements Test { const VERSION = 'C'; public function __construct($name = 'ccc') { } }
class Face
<?php namespace face; interface Test { }
参考文档:https://juejin.im/post/5cac58ecf265da03a85a9f9a#heading-0

更多精彩