DI
DI(Dependency Injection)即为依赖注入。
依赖注入的基本原则是应用组件不应该负责查找资源或者其他依赖的协作对象。
配置对象的工作应该由容器负责,查找资源的逻辑应该从应用组件的代码中抽取出来,交给容器来完成。
DI是对IoC更准确的描述,由容器动态的将某个依赖关系注入到组件之中。
依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。屏蔽调用组件的复杂性。
class DB {
protected $db;
public function select() {
echo '查询数据库的操作方法';
}
}
class User {
protected $db;
public function __construct(DB $db) {
$this‐>db = $db;
}
public function index() {
$this‐>db‐>select();
}
}
IOC
IoC叫控制反转,是 Inversion of Control 的缩写,不是什么技术,而是一种设计思想。
Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。通过容器来实现对象组件的装配和管理。所谓的”控制反转”就是对组件对象控制权的转移,从程序代码本身转移到了外部容器,由容器来创建对象并管理对象之间的依赖关系。
IoC 体现了好莱坞原则 – “Don’t call me, we will call you”。
优点:
- 容器可以自动对你的代码进行初始化,资源集中管理,实现资源的可配置和易管理。
- 降低了使用资源双方的依赖程度,也就是我们说的耦合度。
- 创建实例的时候不需要了解其中的细节
缺点:
- 创建对象的步骤变复杂了,不直观,当然这是对不习惯这种方式的人来说的。
- 因为使用反射来创建对象,所以在效率上会有些损耗。但相对于程序的灵活性和可维护性来说,这点损耗是可以接受的。
原生构建IOC容器可以分为三大步骤来进行容器的构建:
- 绑定对象关系到容器的数组
- 通过反射拿到执行的类构造函数,拿到构造函数的参数
通过反射机制创建 操作对象 ```php <?php namespace KDCAT\Container; use Psr\Container\ContainerInterface; use ReflectionClass; use ReflectionException; use ReflectionParameter; use Exception; class Container implements ContainerInterface{ //注册树 protected $binds = []; /**
- [__construct 构造函数]
- @Author kdcat
- @DateTime 2020-08-04
- @param array $binds [注册类数组]
*/
public function __construct(array $binds = []){
//绑定名称 绑定类名
foreach ($binds as $bindName => $bindClass) {
} } /**$this->set($bindName, $bindClass);
- [set 设置绑定类]
- @Author czt
- @DateTime 2020-08-04
- @param string $bindName [绑定名称]
- @param string $className [类名称]
*/
public function set(string $bindName, string $className)
{
if ($this->has($bindName)) {
} $this->binds[$bindName] = $this->resolve($className); return true; } /**throw new Exception("该名称已被注册:${bindName}", 1);
- [get 返回注册的对象]
- @Author czt
- @DateTime 2020-08-04
- @param string $bindName [description]
- @return [type] [description]
*/
public function get($bindName)
{
if (!$this->has($bindName)) {
} return $this->binds[$bindName]; } /**throw new Exception("未注册的名称${bindName}", 1);
- [has 是否已经注册]
- @Author czt
- @DateTime 2020-08-04
- @param [type] $bindName [description]
@return boolean [description] */ public function has($bindName){ return isset($this->binds[$bindName]); }
/**
- [resolve 递归解决依赖关系]
- @Author czt
- @DateTime 2020-08-04
- @param string $className [description]
- @return [type] [description]
*/
public function resolve(string $className)
{
try{
}catch(\Exception $e){$class = new ReflectionClass($className);
} $obj = null; $inParam = []; //存在构造函数 $constructor = $class->getConstructor(); if ($constructor) {throw new Exception("反射创建失败:${className};".$e->getMessage(), 1);
}else{//获取构造函数的参数 $params = $constructor->getParameters(); foreach ($params as $key => $param) { //获取构造函数的依赖注入类参数 $paramClassName = $param->getClass()->name; $inParam[] = $this->resolve($paramClassName); } $obj = $class->newInstanceArgs($inParam);
} return $obj; } }//不存在构造函数,直接实例化类 $obj = new $className;
AOP
面向切面编程(AOP是Aspect Oriented Program的首字母缩写) ,在项目开发的过程中。面向对象的特点是继承、多态和封装。而封装就要求将功能分散到不同的对象中去,这在软件设计中往往称为职责分配。实际上也就是说,让不同的类设计不同的方法。这样代码就分散到一个个的类中去了。这样做的好处是降低了代码的复杂程度,使类可重用。
比如说,我们在两个类中,可能都需要在每个方法中做日志。按面向对象的设计方法,我们就必须在两个类的方法中都加入日志的方法。也许它们是完全相同的,但就是因为面向对象的设计让类与类之间无法联系,而不能将这些重复的代码统一起来。
可能有同学会说,我们可以将这段代码写在一个独立的类独立的方法里,然后再在这两个类中调用。但是,这样一来,这两个类跟我们上面提到的独立的类就有耦合了,它的改变会影响这两个类。基于这样的问题才有了AOP的诞生。 那如何才能切面呢?
在这种情况出现,我们可动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。
OOP从纵向上区分出一个个的类来,而AOP则从横向上切入到对象中加入特定的代码。AOP算是对OOP编程的一个补充。
总结:就是把相同重复的方法提前出来,然后在注入到需要业务的执行里面。