依赖注入和控制反转

一,概念

要想理解php依赖注入和控制反转两个概念,就必须搞清楚如下的问题:
DI——Dependency Injection 依赖注入
IoC——Inversion of Control 控制反转

  • 参与者
    一般有三方参与者,一个是某个对象;一个是IoC/DI的容器;另一个是某个对象的外部资源。又要名词解释一下,某个对象指的就是任意的、普通的Java对象; IoC/DI的容器简单点说就是指用来实现IoC/DI功能的一个框架程序;对象的外部资源指的就是对象需要的,但是是从对象外部获取的,都统称资源,比如:对象需要的其它对象、或者是对象需要的文件资源等等。
  • 依赖
    某个对象依赖于IoC/DI的容器。依赖是不可避免的,在一个项目中,各个类之间有各种各样的关系,不可能全部完全独立,这就形成了依赖。传统的开发是使用其他类时直接调用,这会形成强耦合,这是要避免的。依赖注入借用容器转移了被依赖对象实现解耦。
  • 注入
    通过容器向对象注入其所需要的外部资源
  • 控制反转
    IoC/DI的容器控制对象,主要是控制对象实例的创建。反转是相对于正向而言的,那么什么算是正向的呢?考虑一下常规情况下的应用程序,如果要在A里面使用C,你会怎么做呢?当然是直接去创建C的对象,也就是说,是在A类中主动去获取所需要的外部资源C,这种情况被称为正向的。那么什么是反向呢?就是A类不再主动去获取C,而是被动等待,等待IoC/DI的容器获取一个C的实例,然后反向的注入到A类中。依赖注入是从应用程序的角度在描述,可以把依赖注入描述完整点:应用程序依赖容器创建并注入它所需要的外部资源;而控制反转是从容器的角度在描述,描述完整点:容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源。

二,实现方式

  • 构造器注入
    将被依赖对象通过构造函数的参数注入给依赖对象,并且在初始化对象的时候注入。
class EmailNotice
{
    public function sendmsg(){
        $str="我是Emali发送消息";
        return $str;
    }
}

class User
{
   public function __construct($notice)
    {
        $this->notice=$notice;
    }

   public function testsend(){
        $rs=$this->notice->sendmsg();
        return $rs;
    }

}

$notice=new EmailNotice();
$user=new User($notice);
$rs=$user->testsend();
echo $rs;
  • setter注入
    IoC Service Provider通过调用成员变量提供的setter函数将被依赖对象注入给依赖类。
class EmailNotice
{
    public function sendmsg(){
        $str="我是Emali发送消息";
        return $str;
    }
}

class User
{
    public function setEmailNotice($notice)
    {
        $this->notice=$notice;
    }

    public function testsend(){
        $rs=$this->notice->sendmsg();
        return $rs;
    }

}

$notice=new User();
$notice->setEmailNotice(new EmailNotice());
$rs=$notice->testsend();
echo $rs;
  • 接口注入
    依赖类必须要实现指定的接口,然后实现该接口中的一个函数,该函数就是用于依赖注入。该函数的参数就是要注入的对象。
interface  NoticeInterface
{
    public function sendmsg();
}
class EmailNotice implements NoticeInterface
{
    public function sendmsg(){
        $str="我是Emali发送消息";
        return $str;
    }
}
class SmsNotice implements NoticeInterface
{
    public function sendmsg(){
        $str="我是短信发送消息";
        return $str;
    }
}
class User
{
    public function __construct(NoticeInterface $notice)
    {
        $this->notice=$notice;
    }
    public function testsend(){
        $rs=$this->notice->sendmsg();
        return $rs;
    }

}

$user=new User(new EmailNotice());
$rs=$user->testsend();
echo $rs;

三,容器

上面几种种方法代码很清晰,但是当我们需要注入很多个依赖时,意味着又要增加很多行,会比较难以管理。比较好的解决办法是 建立一个class作为所有依赖关系的container,在这个class中可以存放、创建、获取、查找需要的依赖关系。

class dog {
    public function eat(){
        echo "dog to eat".PHP_EOL;
    }
}
//几个概念
//Closure用于代表 匿名函数 的类
//instanceof 用于确定一个 PHP 变量是否属于某一类 class 的实例来确定一个变量是不是继承自某一父类的子类的实例
//call_user_func_array 调用回调函数,并把一个数组参数作为回调函数的参数
//array_unshift  在数组开头插入一个或多个单元
class Container{
    protected $binds;
    protected $instances;

    public  function bind($abstract,$concrete){
        if ($concrete instanceof Closure) { // 判断是不是闭包化
            $this->binds[$abstract] = $concrete;
        } else {
            $this->instances[$abstract] = $concrete;// 正常实例化
        }
    }

    public function make($abstract,$parameters=[]){
        if (isset($this->instances[$abstract])) {
            return $this->instances[$abstract];
        }
        array_unshift($parameters, $this);
        return call_user_func_array($this->binds[$abstract], $parameters);
    }
}

实现绑定注册和使用

$obj = new Container;
$dog = new dog();
$obj->bind('Dog',$dog);
$want_eat = $obj->make('Dog');
$want_eat->eat();
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值