让我们看一个例子:

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 类注入而不需要直接使用它。

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

将组件注入类时,可以使用以下三个选项之一:

构造方法注入

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 方法来解决依赖关系。

优势

现在,当测试我们的类时,我们可以模拟依赖类并将其作为参数传递。每个类必须专注于一个特定的任务,而不应该关心解决它们的依赖性。这样,你将拥有一个更专注和可维护的应用程序。

======================= 华丽的分割线 ===================   目录结构:  依赖注入demo 随笔

部分代码:

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

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄