php ioc容器特点,研究PHP Ioc容器和依赖注入 · Sinchie's Blog

控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机进程的耦合问题。 控制反转一般分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。依赖注入应用比较广泛。没接触过的同学,看了上面的介绍一定会想这是什么玩意儿,好像无比high big up。下面笔者就把自己的理解来告诉大家。

依赖注入

假设我们这里有一个类 A,可以看出在构造方法中引入了数据库类,并且实例化它存入到自身属性,方便其他方法调用。看上去我们实现了想要的功能,但是这是一个噩梦的开始。A,B,C,D,E 越来越多的类需要数据库类,如果都这么写的话,万一有一天数据库密码改了或者db类发生变化了,岂不是要回头修改所有类文档?class A {

private $db;

public function __construct()

{

include "./Lib/Db.php";

$this->db = new Db("localhost","root","123456","test");

}

public function getList()

{

$this->db->query("......");

}

...

}

好吧,为了解决这个问题,下面的 工厂模式 出现了,我们创建了一个Factory方法,并通过 Factory::getDb() 方法来获得db组件的实例。class Factory {

public static function getDb(){

include "./Lib/Db.php";

return new Db("localhost","root","123456","test");

}

...

}

class A {

private $db;

function __construct(){

$this->db = Factory::getDb();

}

function getList(){

$this->db->query("......");

}

...

}

现在出现数据库密码变了等情况,直接去修改工厂类里面的getDb方法就行了。实际上你由原来的直接与Db类的耦合变为了和Factory工厂类的耦合。但是突然有一天工厂方法需要改名,或者getDb方法需要改名,你又怎么办?当然这种需求其实还是很操蛋的,但有时候确实存在这种情况。一种解决办法是,我们不在A类内部实例化数据库组件,转移到外部,从外部注入。class A {

private $db;

//从外部注入db连接(构造方法注入也可以)

function setDb($connection){

$this->db = $connection;

}

function getList(){

$this->db->query("......");

}

...

}

//调用

$a = new A();

$a->setDb(Factory::getDb());//注入db连接

$a->getList();

这样一来,A 类完全与外部类解除耦合了,你可以看到 A 类里面已经没有工厂方法或Db类的身影了。我们通过从外部调用工厂类的 setDb 方法,将连接实例直接注入进去。这样 A 完全不用关心db连接怎么生成的了,这就叫 依赖注入 。A类依赖于Db类,实现不是在代码内部创建依赖关系,而是让其作为一个参数传递,这使得我们的进程更容易维护,降低进程代码的耦合度,实现一种松耦合。

这还没完,假设A类还依赖其他很多类呢?$A->setDb(Factory::getDb());//注入db连接

$A->setFile(Factory::getFile());//注入文档处理类

$A->setImage(Factory::getImage());//注入Image处理类

...

当然我们还可以创建一个工厂方法 Factory::getA() ,用来处理A类的依赖。class Factory {

public static function getA(){

$a = new A();

$a->setDb(Factory::getDb());//注入db连接

$a->setFile(Factory::getFile());//注入文档处理类

$a->setImage(Factory::getImage());//注入Image处理类

return $a;

}

}

//调用A类变为

$a = Factory::getA();

$a->getList();

似乎完美了,但是怎么感觉又回到了上面第一次用工厂方法时的场景?这确实不是一个好的解决方案,所以又提出了一个概念:容器,又叫做IoC容器、DI容器。他能帮我们管理依赖关系。把所有类绑定到容器中,在调用类时会自动检测依赖关系,自动从容器中加载依赖的类,就不用我们手动写这么多set了。

Ioc容器

先看看效果,假设现在有三个类 A,B,C。之间的关系是 C依赖于B,B依赖于A。class A {

public function say()

{

echo 'i am A
';

}

}

class B {

private $a;

public function __construct(A $a) //注入A的实例

{

$this->a = $a;

}

public function say()

{

$this->a->say();

echo 'i am B
';

}

}

class C {

private $b;

public function __construct(B $b)

{

$this->b = $b;

}

public function say()

{

$this->b->say();

echo 'i am C
';

}

}

现在把他们都注册到容器中,假设容器类叫 App。$app = new App();

$app->bind('a','A'); //将A注册到容器中,小写a是在容器中的别名,大写A是类的全称

$app->bind('b','B');

$app->bind('c','C');

//调用B的say方法

$b = $app->make('b');

$b->say();

//结果

i am A

i am B

//调用C的say方法

$c = $app->make('c');

$c->say();

//结果

i am A

i am B

i am C

发现没有?我们彻底的解除了类和类的依赖关系,达到了比较高的解耦。更重要的是,容器类也丝毫没有和他们产生任何依赖!实现了控制反转。而且注入容器中的类,只有在make时才会实例化它。这是我写的一个容器demo,主要用到了PHP的反射去抓取依赖的类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值