什么是依赖注入?

先看一段伪代码

class DB{
    private $db;//这里可能是pdo 可能是别的,仅仅为了演示
    public function __construct($connInfo)
    {
        //.....做些pdo或者mysqli等初始化工作

    }
    public function queryForRows($sql){
        return ['id'=>101,"username"=>"qidong"];
    }
}
class MyUser{
    private $mydb;
    
    public function __construct($dsn)
    {    //$dsn当做可以连接的字符串。
         $this->mydb=new DB($dsn);
         //主动实例化
    }
    public function getAllUsers():array{
         //是业务方法
         return $this->mydb->queryForRows("select * from users");
    }
}

$user=new MyUser("mysql:host=localhost;");
var_dump($user->getAllUsers());

上面缺点非常明显:


MyUser简称为A。 Db简称为B

两个类过于耦合。我们把MyUser和数据库两个概念 混淆在了一起 ,变成了一个。当数据库密码或者其他信息更换,我们要从MyUser的构造函数传参数,去修改Db类。调用方式属于先调用A—->B。正向关系。

修改后代码:

class MyUser{
    private $mydb;
    
    public function __construct(DB $db)
    {    //强制要求类型是DB类
         $this->mydb=$db;
         
    }
    public function getAllUsers():array{
         //是业务方法
         return $this->mydb->queryForRows("select * from users");
    }
}

$db=new DB("mysql:host=localhost;");
$user=new MyUser($db);
var_dump($user->getAllUsers());

依赖注入Dependency Injection (DI):个人理解。调用A类的时候。A类需要的依赖参数,不是A类的内部生成。而是以外部注入的方式传入。

控制反转Inversion of Control (IoC):和正向调用相反,我使用A必须在之前调用B。就叫控制反转。执行顺序B—>A。

IOC容器的概念。就是加了一个存储对象的容器而已。

IOC容器的简单实现


class Container
{
    private static $container=[];
    public static function set(string $name,callable $func)
    {
        self::$container[$name]=$func;
    }

    /**
     *
     * @param string $name
     * @return null
     */
    public static function get(string $name)
    {
        if(isset(self::$container[$name])){
            //下面代码可以理解立即执行闭包函数
            return (self::$container[$name])();
        }
        return null;
    }
}
Container::set('MyDb',function(){
    return new MyDb('xx');
});

Container::set('MyUser',function(){
    return new MyUser(Container::get('MyDb'));
});

$MyUser=Container::get('MyUser');
var_dump($MyUser->getAllUsers());
Last modification:January 31, 2020
如果觉得我的文章对你有用,请随意赞赏