tags: 容器 依赖注入 IOC DI 控制反转
引言: 如果你看过一些框架的源码或者手册, 像是 laravel 或者 tp5 之类的, 应该会提到容器, 依赖注入, 控制反转等词汇或者是某些面试官会问到这类问题希望这篇文章能让你有所收获
1.1IoC(控制反转 Inversion of Control)
简述: 控制反转并不是一种技术, 而是一种设计思想通过控制反转容器(以后称容器), 改变了原本某些对象运行时依赖其他对象资源时需要自己进行获取(比如通过 new ClassName), 所造成的对象之间的强耦合(耦合的概念如果不理解, 可以先去了解一下)
所谓 IoC, 对于程序来说, 就是构造了一个容器, 比如在 tp5 中, 这个容器叫 Container, 此容器来负责控制对象和对象间的关系在一个对象中, 如果要使用另外的对象, 就必须得到它 (自己 new 一个), 这样的话一个对象 A 和另一个对象 B 之间就有了很强的联系(也就是强耦合) 这种耦合体现在如果被依赖的资源类初始化的时候 (也可能是其他时候) 传入的参数变化了, 你要修改两个类的代码, 举例说明:
你本来用的是 php 本身的 session 机制, 现在想改成也支持 redis, 并在初始化的时候增加一个参数来控制这个时候你不止需要去修改类 Session 类的代码, 还要去修改类 A 的代码部分代码如下
- // 原代码
- class Session{
- function __construct(){
- //balabala
- }
- }
- class A{
- protected $driver;
- function __construct(){
- $this->driver = new Session();
- }
- }
- // 需要增加一种 redis 方式后修改为
- class Session{
- protected $driver;
- function __construct(string $driver=''){
- if($driver === ''){
- //balabala
- }else if($driver === 'redis'){// 增加了一种模式
- //balabala
- }else{
- //balabala
- }
- }
- }
- class A{
- protected $driver;
- function __construct(){
- $this->driver = new Session('redis');// 我想使用 redis 了
- }
- }
可以看到, 不止我们修改了 B 的代码, 还要去修改 A 的代码, 这样如果依赖关系多起来的话, 每次修改 A 依赖的对象, 可能要处理 A 中很多条代码会造成对象之间的强耦合所以我们可以把 A 需要的东西, 在 A 之前就创建出来, 并通过构造函数参数传递给 A 代码如下
- class A{
- protected $driver;
- function __construct(A $a){
- // 我想使用 redis 了
- }
- }
- $driver = new Session('redis');// 我想使用 redis 了
- $a = new A($driver)
这种方法下更改 A 依赖的所有对象都通过构造方法或者其他方法的形式给 A, 这些对象本身机制更改的时候就无需修改 A 的代码了但是每次自己使用 A 的时候都去看看 A 需要些什么在前面都 new 一遍, 感觉上很 low 啊, 不如我们搞一个管家(容器), 如果发现你需要什么, 管家就给你什么这样所依赖的类的创建都由容器来控制, 也就是说控制对象创建的不再是引用它的对象, 而是容器对于某个具体的对象而言, 以前是它控制其他对象, 需要什么自己处理, 现在是所有对象都被容器控制, 所以控制反转是一种控制权的转移
1.2DI(依赖注入 Dependency Injection Container)
IoC 的一个重点是在系统运行中, 动态的向某个对象提供它所需要的其他对象这一点是通过 DI(Dependency Injection, 依赖注入, 或者叫依赖注入容器)来实现的比如还是上面的例子, 对象 A 需要操作 Session, 以前我们总是要在 A 中自己编写代码来获得一个 Session 对象, 有了 容器这个管家我们就只需要告诉容器, A 中需要一个 Session 对象, 至于这个 Session 对象怎么构造, 何时构造, A 不需要知道在系统运行时, 容器会在适当的时候制造一个 Session, 通过构造方法注射到 A 当中, 这样就完成了对各个对象之间关系的控制, 而且这种关系是松耦合的
A 需要依赖 Session 才能正常运行, 而这个 Session 是由容器注入到 A 中的, 依赖注入的名字就这么来的那么 DI 是如何实现的呢? php 有一个高级特性是反射(reflection), 原理这里大概说一下,
反射可以在 php 运行中, 提取出关于类方法属性参数, 注释等的详细信息, 并可以动态的调用方法和类等这种动态获取的信息以及动态调用对象的方法的功能称为反射 API
反射允许程序在运行的时候动态的生成对象执行对象的方法改变对象的属性, 容器就是通过反射来实现注入的
总结:
控制反转是说创建对象的控制权进行转移, 由原来的资源需求方, 转移到了容器, 依赖注入是说本来是资源需求方依赖资源, 现在资源需求方依赖于容器对资源的注入, 可以看出来依赖注入和控制反转说的其实是一个事情
顺便提一句, 目前很多框架中都离不开反射功能容器是一个典型的例子, 容器在 laravel 和 tp5 中都是核心功能之一
来源: https://www.cnblogs.com/vinter/p/8670032.html