-
PHP 控制反转和依赖注入(IoC/DI)
2017-09-22 20:14:43依赖注入的目的是实现松耦合的软件架构,以便更好的测试,管理和扩展的代码。 控制反转(Inversion of Control):当调用者需要被调用者的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例,但...依赖注入的目的是实现松耦合的软件架构,以便更好的测试,管理和扩展的代码。
控制反转(Inversion of Control):当调用者需要被调用者的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例,但在这里,创建被调用者的工作不再由调用者来完成,而是将被调用者的创建移到调用者的外部,从而反转被调用者的创建,消除了调用者对被调用者创建的控制,因此称为控制反转。
依赖注入(Dependency Injection):要实现控制反转,通常的解决方案是将创建被调用者实例的工作交由IoC容器来完成,然后在调用者中注入被调用者(通过构造器/方法注入实现),这样我们就实现了调用者与被调用者的解耦,该过程被称为依赖注入。依赖注入是控制反转的一种实现方式。常见注入方式有三种:setter、constructor injection、property injection。
容器(Container):管理对象的生成、资源取得、销毁等生命周期,建立对象与对象之间的依赖关系,可以延时加载对象。比较著名有PHP-DI、Pimple。
代码演示IoC:
假设应用程序有储存需求,若直接在高层的应用程序中调用低层模块API,导致应用程序对低层模块产生依赖。
假设程序要移植到另一个平台,而该平台使用USB磁盘作为存储介质,则这个程序无法直接重用,必须加以修改才行。本例由于低层变化导致高层也跟着变化,不好的设计。程序不应该依赖于具体的实现,而是要依赖抽像的接口。请看代码演示:<?php /** * 高层 */ class App { private $writer; public function __construct() { $this->writer = new FloppyWriter(); } public function save() { $this->writer->saveToFloppy(); } } /** * 低层,软盘存储 */ class FloppyWriter { public function saveToFloppy() { echo __METHOD__; } } $app = new App(); $app->save(); // FloppyWriter::saveToFloppy
控制权从实际的FloppyWriter转移到了抽象的IDeviceWriter接口上,让App依赖于IDeviceWriter接口,且FloppyWriter、UsbDiskWriter也依赖于IDeviceWriter接口。<?php /** * 接口 */ interface IDeviceWriter { public function saveToDevice(); } /** * 高层 */ class App { /** * @var IDeviceWriter */ private $writer; /** * @param IDeviceWriter $writer */ public function setWriter($writer) { $this->writer = $writer; } public function save() { $this->writer->saveToDevice(); } } /** * 低层,软盘存储 */ class FloppyWriter implements IDeviceWriter { public function saveToDevice() { echo __METHOD__; } } /** * 低层,USB盘存储 */ class UsbDiskWriter implements IDeviceWriter { public function saveToDevice() { echo __METHOD__; } } $app = new App(); $app->setWriter(new UsbDiskWriter()); $app->save(); // UsbDiskWriter::saveToDevice $app->setWriter(new FloppyWriter()); $app->save(); // FloppyWriter::saveToDevice
这就是IoC,面对变化,高层不用修改一行代码,不再依赖低层,而是依赖注入,这就引出了DI。如果这个组件有很多依赖,我们需要创建多个参数的setter方法来传递依赖关系,这让我们的代码不易维护。
<?php //创建依赖实例 $request = new Request(); $filter = new Filter(); //把实例作为参数传递给构造函数 $some = new SomeComponent($request, $filter); $some->setRequest($request); $some->setFilter($filter);
解决的方法是为依赖实例提供一个容器。这个容器担任全局的注册表,注入容器而不是具体实例。
这个组件现在可以很简单的获取到它所需要的服务,服务采用延迟加载的方式,只有在需要使用的时候才初始化,这也节省了服务器资源。这个组件现在是高度解耦。<?php class SomeComponent { protected $_di; public function __construct($di) { $this->_di = $di; } public function someRequest() { // 请求实例 $connection = $this->_di->get('request'); } public function someOtherRequest() { // 请求实例 $connection = $this->_di->get('request'); // 过滤器实例 $filter = $this->_di->get('filter'); } } $di = new DI(); //在容器中注册一个request服务 $di->set('request', function() { return new Request(array( "test" => "test" )); }); //在容器中注册一个filter服务 $di->set('filter', function() { return new Filter(); }); //把传递服务的容器作为唯一参数传递给组件 $some = new SomeComponent($di); $some->someRequest();
-
php的控制反转和依赖注入
2019-07-04 17:40:131.判断代码的好处就是高内聚低耦合 ...而在代码中体现出来的设计模式就是依赖注入和控制反转 2.依赖注入: 就是A类所依赖的B类C类等以属性或者构造函数等方式注入A类而不是直接在A类中实例化。 例如: class A { p...1.判断代码的好处就是高内聚低耦合
高内聚就是软件模块是由相关性很强的代码组成,只负责一项任务,也就是常说的单一责任原则。
低耦合就是每个模块之间耦合度要低,如果要修改,修改一点点就可以而不是修改一大部分。
而在代码中体现出来的设计模式就是依赖注入和控制反转
2.依赖注入:
就是A类所依赖的B类C类等以属性或者构造函数等方式注入A类而不是直接在A类中实例化。
例如:class A { public $b; public $c; public function __construct() { //TODO } public function method() { $this->b=new B(); $this->c=new C(); $this->b->method(); $this->c->method(); //TODO } } class B { public function __construct() { //TODO } public function method() { //TODO echo 'b'; } } class C { public function __construct() { //TODO } public function method() { //TODO echo 'c'; } } $a=new A(); $a->method();
上面中A类中依赖了B和C类,如果后期开发中涉及函数改名,就会牵动到a类的整个都需要修改。有没有方法真的修改了B和C类,尽量也不要去改动A呢?这里要用到控制反转,就是现在是b和c控制着a,我们要反转过来,a这边可以主动控制,不管b和c改成什么。控制反转(IOC)是一种思想,依赖注入(ID)是实施这种思想的方法。
第一种方法:构造器注入(不推荐使用,但比不用好)class A{ public $b; public $c; public function __construct($b,$c){ $this->b=$b; $this-<c=$c; } public function method(){ $this->b->method(); $this->c->method(); } } 这样调用 $a = new A(new B(),new C()); $a->method();
第二种方法:工厂模式注入
class Factory { public function Factory() { //TODO } public function create($s) { switch($s) { case 'B': { return new B(); break; } case 'C': { return new C(); break; } default: { return null; break; } } } }
然后把A类改成这样
class A { public $b; public $c; public function __construct() { //TODO } public function method() { $f=new Factory(); $this->b=$f->create('B'); $this->c=$f->create('C'); $this->b->method(); $this->c->method(); //TODO } }
这样至少如果B和C类的构造函数发生变化,比如修改参数时,只需要修改Factory类就可以了。
把B类和C类的方法再抽象出来,做一个接口.
这样,A类中的b变量和c变量就不再是一个具体的变量了,而是一个抽象类型的变量,不到运行那一刻,不知道他们的Method方式是怎么实现的。interface IMethod { public function method(); } class B implements IMethod { public function __construct() { //TODO } public function method() { //TODO echo 'b'; } } class C implements IMethod { public function __construct() { //TODO } public function method() { //TODO echo 'c'; } }
总结:
1.我们把A类中的B类对象和C类对象的创建移至A类外
2.原本A类依赖B类和C类,现在变成了A依赖Factory,Factory依赖B和C。 -
php 依赖注入 数据库切换_ThinkPHP容器之控制反转和依赖注入
2021-01-15 19:16:50三、如何理解控制反转和依赖注入其实这俩个就是指的一个东西,就是一种编程思想而已,不要想的那么难以理解和高大上。那么什么是容器,容器直面理解就是装东西的东西。在编程中,我们常见的变量、对象属性都是一个...依赖注入控制反转名字听起来很迷,看了本文你就知道它是个什么玩意了。
三、如何理解控制反转和依赖注入
其实这俩个就是指的一个东西,就是一种编程思想而已,不要想的那么难以理解和高大上。
那么什么是容器,容器直面理解就是装东西的东西。在编程中,我们常见的变量、对象属性都是一个容器。一个容器里边能够装什么,完全取决于对该容器的定义。
然而现在我们讨论的是另外一种容器,它存储的既不是文本、数值,而是对象、类、接口通过这种容器,得以实现很多高级功能,最常用的就是代码之间的解耦、依赖注入。
那么为什么会存在俩种概念,为什么要说控制反转和依赖注入呢!在上文也提到过,它们其实指的就是一种东西,只是描述的角度不同而已。
就跟你是爸爸的儿子,你还是你爷爷的孙子,不管儿子还是孙子都指的是一个人。只是站在不同的角度看待问题而已。
控制反转
是站在容器的角度看待问题,容器控制着应用程序,由容器反向的向应用程序注入应用程序需要的外部资源。
依赖注入
是站在应用程序的角度看待问题,应用程序依赖容器创建并注入它所需要的外部资源。
作用
主要用来减少代码之间的耦合程度。
有效的分离对象和应用程序所需要的外部资源。
下面俩幅图就可以很清晰的说明问题
给大家整一个简单的案例
定义俩个类分别为Person、Car,在Person中实例并调用Car中的pay方法。
然后在控制器中调用,并且打印结果肯定就是Car返回的123,这个就不去打印了。
在这里插入图片描述
那这个时候我们把代码修改一下,把Car类直接传给Person类,在Person类中直接用传过来的对象去调用对应的方法。
这只是一个简单的实现过程,为了给阅读框架容器代码做一个铺垫,在后文中会详细说明框架中的容器注入。坚持学习、坚持写博、坚持分享是咔咔从业以来一直所秉持的信念。希望在偌大互联网中咔咔的文章能带给你一丝丝帮助。我是咔咔,下期见。
-
PHP的控制反转和依赖注入以及反射
2019-06-23 22:26:34控制反转,依赖注入 这里先不说概念,只先看两个最小修普通的小demo; 在routine这个文件里,先创建一下几个文件: InterfaceLog.php 声明的一个接口文件 FileLog.php 这个实现上面接口的类 DatabaseLog.php 这个...控制反转,依赖注入
这里先不说概念,只先看两个最小修普通的小demo;
在
routine
这个文件里,先创建一下几个文件:- InterfaceLog.php 声明的一个接口文件
- FileLog.php 这个实现上面接口的类
- DatabaseLog.php 这个实现上面接口的类
- User.php 这个具体的操作类
一下是代码实现:
interface InterfaceLog { public function write(); } class FileLog implements InterfaceLog { public function write() { // TODO: Implement write() method. var_dump('文件日志模式'); } } class DatabaseLog implements InterfaceLog { public function write() { // TODO: Implement write() method. var_dump('数据库日志模式'); } } class User { private $file; public function __construct() { $this->file = new FileLog(); } public function login() { echo 'login is success!!!'; $this->file->write(); } } $user = new User(); $user->login();
在这个具体的user类里,有一个构造方法,有一个私有函数,在构造函数里,实例化不同的类赋值给私有变量file.
也就是,要实现不同的方式来写日志,就需要来改这个user类的控制器里的赋值方法。接下来,实现一个灵活点的例子,就是改变不同方式日志写的方式的时候,不需要去改这个类内部的代码。
具体需要在controller里创建的文件:- 定义一个接口文件,Logs.php
- 文件方式实现写日志的类,FileLog.php
- 数据库方式实现写日志的类,DatabaseLog.php
- 具体的逻辑处理类
interface Logs { public function write(); } class FileLog implements Logs { public function write() { // TODO: Implement write() method. var_dump('文件记录日志'); } } class DatabaseLog implements Logs { public function write() { // TODO: Implement write() method. var_dump('数据库记录日志'); } } class User { private $file; public function __construct(DatabaseLog $log) { $this->file = $log; } public function login() { var_dump('login is success!!!'); $this->file->write(); } } $user = new User(new DatabaseLog()); $user->login();
在这里,就不需要改变逻辑类里面的代码,想要改用不同的写文件的方法,只需要在实例化user类的时候,传递不同的
实现Logs的接口类就可以了。从上面的两个例子就可以看出,在改变程序内部需求的时候,不需要改变内部的依赖关系,而是靠从外面传递参数,进而改变类内部的依赖的方法,也就是控制反转。
控制反转IOC(inversion of control): 控制反转是将组件间的依赖关系从程序内部提到外部来管理,说了控制反转,那就不能不说依赖注入。它们一般就是难兄难弟的关系,使用的时候也是差不多一起出现的。
依赖注入DI(dependency injection):依赖注入是指将组件的依赖通过外部以参数或其他形式注入在laravel这个框架中,这两个使用的还是比较多的,比如最常见的就是,在控制器的方法里,通过
request
类的方法的接受参数的时候,如下:<?php class User { public function store(\Illuminate\Http\Request $request) { $params = $request->all(); //或者 $id = $request->get('id'); } }
说到这里,可能我们还需要知道一个词就是 反射 PHP反射
PHP自5.0版本以后添加了反射机制,它提供了一套强大的反射API,允许你在PHP运行环境中,访问和使用类、方法、属性、参数和注释等,其功能十
分强大,经常用于高扩展的PHP框架,自动加载插件,自动生成文档,甚至可以用来扩展PHP语言。由于它是PHP內建的oop扩展,为语言本身自带的特
性,所以不需要额外添加扩展或者配置就可以使用这里可以做拿User类做一下测试:
//获取User的reflectionClass对象 $reflector = new reflectionClass(User::class); var_dump($reflector); //得到user的构造函数 $controller = $reflector->getConstructor(); var_dump($controller); // 拿到User的构造函数的所有依赖参数 $params = $controller->getParameters(); var_dump($params); // 创建user对象,没有参数的 $user = $reflector->newInstance(); var_dump($user); $user->login();
以上是构造函数没有参数的情况下,就很简单就构造了user类,并且调用login()方法也是成功了。
简单封装一下:
public function make($class) { // 获取User的reflectionClass对象 $reflector = new \reflectionClass($class); //得到构造函数 $controller = $reflector->getConstructor(); //判断构造函数 if (!is_null($controller)) { //得到构造函数的参数,依赖项 $params = $controller->getParameters(); //判断是否有依赖项 if (is_null($params)) { //直接得到对象 $result = $reflector->newInstance(); } else { //有参数,递归创建 $instances = $this->recursionMake($params); $result = $reflector->newInstanceArgs($instances); } } else { $result = $reflector->newInstance(); } return $result; } public function recursionMake($params) { $recursionMake = []; foreach ($params as $param) { $recursionMake[] = $this->make($param->getClass()->name); } return $recursionMake; }
到这里,反射基本就出来了,就是要熟悉一下PHP的反射类:
- 反射类
reflectionClass
- 通过反射类得到构造函数
getConstructor()
- 通过构造函数得到依赖参数
getParameters()
- 没有依赖项的直接创建
newInstance()
- 有依赖项的递归创建,最后再根据我们得到的参数,创建我们得到的类
newInstanceArgs()
继续简要实现laravel ioc容器
class Ioc { public $binding = []; public function buid($abstract, $concrete) { $this->binding[$abstract]['concrete'] = function ($ioc) use ($concrete) { return $ioc->build($concrete); }; } public function make($abstract) { $concrete = $this->binding[$abstract]['concrete']; return $concrete; } public function build($class) { $reflector = new \reflectionClass($class); //得到构造函数 $controller = $reflector->getConstructor(); //判断构造函数是否存在 if (is_null($controller)) { $result = $reflector->newInstance(); } else { //得到依赖项 $params = $controller->getParameters(); //判断是否有依赖项 if (is_null($params)) { $result = $reflector->newInstance(); } else { $inctances = $this->recursionBuild($params); $result = $reflector->newInstanceArgs($inctances); } } return $result; } public function recursionBuild($params) { $recursionBuild = []; foreach ($params as $param) { $recursionBuild[] = $this->build($param->getClass()->name); } return $recursionBuild; } }
-
PHP的反射、控制反转和依赖注入
2020-07-20 14:43:48Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。传统程序设计,我们直接在对象内部通过new进行创建对象,是... -
php设计模式3--控制反转、依赖注入
2019-04-08 11:09:53在说到设计模式的时候,就不得不提这两个经典的设计模式控制反转(IOC)和依赖注入(DI)。在框架当中是两个非常重要的设计模式,如laravel框架的核心就是一个IOC容器。这篇文章暂时不会涉及在框架中的使用,仅会从... -
依赖注入与控制反转_PHP控制反转(IOC)和依赖注入(DI)
2021-01-13 03:00:18IOC(inversion of control)控制反转模式;控制反转是将组件间的依赖关系从程序内部提到外部来管理; DI(dependency injection)依赖注入模式;依赖注入是指将组件的依赖通过外部以参数或其他形式注入; 两个说法... -
控制反转和依赖注入的理解(通俗易懂)_15 PHP 设计模式系列「依赖注入模式(Dependency Injection)」...
2020-11-20 15:07:141、模式定义依赖注入(Dependency Injection)是控制反转(Inversion of Control)的一种实现方式。我们先来看看什么是控制反转。当调用者需要被调用者的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的... -
理解php依赖注入和控制反转
2020-10-22 09:49:52主要帮助大家理解php依赖注入和控制反转,感兴趣的小伙伴们可以参考一下 -
依赖注入与控制反转_PHP的依赖注入(DI) 和 控制反转(IoC)
2021-01-13 03:00:05DI - Dependency Injection 依赖注入依赖注入和控制反转说的实际上是同一个东西,它们是一种设计模式,这种设计模式用来减少程序间的耦合依赖注入是从应用程序的角度在描述,可以把依赖注入,即:应用程序依赖容器... -
依赖注入与控制反转_PHP的控制反转(IOC)和依赖注入(DI)概念
2021-01-05 08:56:04IOC(inversion of control)控制反转模式;控制反转是将组件间的依赖关系从程序内部提到外部来管理; DI(dependency injection)依赖注入模式;依赖注入是指将组件的依赖通过外部以参数或其他形式注入; 两个说法本质... -
简单理解Laravel中的控制反转和依赖注入 (非权威,仅供参考)
2020-07-08 15:17:25首先从概念上来说,依赖注入是控制反转的一种具体实现。 而从PHP面向对象的角度来说,控制反转是想解决,A类依赖于B类,而在一般情况下A类想要使用B类的方法,需要先New一个B类。所以对于B类的控制权在于A类手中。 ... -
php 依赖注入 和控制反转
2019-09-17 01:15:34Inversion of control 中文名称:控制反转/依赖注入 通常情况下:调用者来创建被调用者的实例,例如。 class a{} class b{ public function t(){ $c = new a(); ... -
PHP控制反转(IOC)和依赖注入(DI)
2020-10-20 04:55:30本文主要介绍了PHP控制反转(IOC)和依赖注入(DI)的相关知识。具有很好的参考价值。下面跟着小编一起来看下吧 -
理解 PHP 依赖注入 和 控制反转
2019-03-19 16:42:00要想理解 PHP依赖注入和控制反转两个概念,就必须搞清楚如下的两个问题: DI—— Dependency Injection 依赖注入 IoC—— Inversion of Control 控制反转 什么是依赖注入 没有你我就活不下去,那么,你就是... -
php 依赖注入 数据库切换_谈谈php依赖注入和控制反转
2020-12-21 05:35:45要想理解php依赖注入和控制反转两个概念,就必须搞清楚如下的问题:DI——Dependency Injection 依赖注入IoC——Inversion of Control 控制反转1、参与者都有谁?答:一般有三方参与者,一个是某个对象;一个是IoC/... -
php 依赖注入 数据库切换_php的依赖注入和控制反转
2020-12-30 14:38:20依赖注入(DI)和控制反转(IOC)基本是一个意思,因为说起来谁都离不开谁。简单来说,a依赖b,但a不控制b的创建和销毁,仅使用b,那么b的控制权交给a之外处理,这叫控制反转(IOC),而a要依赖b,必然要使用b的instance,... -
php 依赖注入 数据库切换_php 依赖注入 和 控制反转 php设计模式
2021-01-12 22:04:19IOC:英文全称:Inversion of Control,中文名称:控制反转,它还有个名字叫依赖注入(Dependency Injection,简称DI)。当一个类的实例需要另一个类的实例协助时,在传统的程序设计过程中,通常由调用者来创建被调用者... -
php依赖注入和控制反转
2019-12-30 21:34:08依赖注入是一种设计模式,又名 控制反转 ,为了降低耦合度 1:控制反转(Inversion of Control )的实现方式 简称:IOC 理解:A类不需要主动去获取C,而是被动等待,等待IoC/DI的容器获取一个C的实例,然后反向的...
-
数据库面试题【八、关系型数据库和非关系型数据库区别】
-
华为1+X——网络系统建设与运维(中级)
-
C/C++反汇编解密
-
利用python快速查找某个路径下的所有指定格式文件
-
抖音任务点赞平台源码.zip
-
日本三菱公司FX系列PLC通信调试工具(含源代码)
-
MySQL 性能优化(思路拓展及实操)
-
HBase 数据存储结构
-
Scanner类 通过Scanner类来获取用户的输入
-
linux环境下的mount命令到底有什么玄机
-
金士顿U盘微博营销活动策划方案.ppt
-
占据主动!刘强东微博营销之道.pdf
-
Redis Desktop Manager_023210734.exe
-
Mycat 实现 MySQL的分库分表、读写分离、主从切换
-
各种格式测试视频(.avi.wmv.mkv.mp4.mov.rm)
-
linux软件的安装应该都有两种方式,一种连网的安装(二进制方式安装),一种不联网的安装(源码方式安装),ROS功能包也是如此。
-
工程制图 AutoCAD 2012 从二维到三维
-
【考研初试】安徽建筑大学501建筑设计考研真题库资料
-
基于电商业务的全链路数据中台落地方案(全渠道、全环节、全流程)
-
鸿蒙系统Harmonyos源码架构分析-第1期第2课