一个没有绝对答案的世界,却拥有绝对的丰富。 --《沈奇岚:我愿生命从容》

2.11.1 定义

(1) 关于依赖注入

即控制反转,目的是了减少耦合性,简单来说就是使用开放式来获取需要的资源。

(2) 关于资源

这里说的资源主要是在开发过程中使用到的资源,包括配置项;数据库连接、Memcache、接口请求等系统级的服务;以及业务级使用到的实例等。

引入依赖注入的目的不仅是为了增加一个类,而是为了更好的对资源进行初始化、管理和维护。下面将进行详细的说明。

2.11.2 一个简单的例子

很多时候,类之间会存在依赖、引用、委托的关系,如A依赖B时,可以这样使用:

classA{

protected$_b;

publicfunction__construct()

{

$this->b=newB();

}

}

这种方式在A内限制约束了B的实例对象,当改用B的子类或者改变B的构建方式时,A需要作出调整。这时可以通过依赖来改善这种关系:

classA{

protected$_b;

publicfunction__construct($b)

{

$this->b=$b;

}

}

再进一步,可以使用DI对B的对象进行管理:

classA{

publicfunction__construct()

{

}

publicfunctiondoSth()

{

//当你需要使用B时

$b=$di->get('B');

}

}

这样的好处?

一方面,对于使用A的客户(指开发人员),不需要再添加一个B的成员变量,特别不是全部类的成员函数都需要使用B类服务时。另一方面在外部多次初始化A实例时,可以统一对B的构建。

2.11.3 依赖注入的使用示例

为方便使用,调用的方式有:set/get函数、魔法方法setX/getX、类变量$fdi->X、数组$fdi['X'],初始化的途径有:直接赋值、类名、匿名函数。

/**------------------创建与设置------------------**/

//获取DI

$di=DI();

//演示的key

$key='demoKey';

/**------------------设置------------------**/

//可赋值的类型:直接赋值、类名赋值、匿名函数

$di->set($key,'HelloDI!');

$di->set($key,'Simple');

$di->set($key,function(){

returnnewSimple();

});

//设置途径:除了上面的set(),你还可以这样赋值

$di->setDemoKey('HelloDI!');

$di->demoKey='HelloDI!';

$di['demoKey']='HelloDI!';

/**------------------获取------------------**/

//你可以这样取值

echo$di->get('demoKey'),"\n";

echo$di->getDemoKey(),"\n";

echo$di->demoKey,"\n";

echo$di['demoKey']."\n";

/**

*演示类

*/

classSimple

{

publicfunction__construct()

{

}

}

2.11.4 依赖注入的好处

(1)减少对各个类编写工厂方法以单例获取的开发量

DI相当于一个容器,里面可以放置基本的变量,也可以放置某类服务,甚至是像文件句柄这些的资源。在这容器里面,各个被注册的资源只会存在一份,也就是当被注册的资源为一个实例对象时,其效果就等于单例模式。

因此,保存在DI里面的类,不需要再编写获取单例的代码,直接通过DI获取即可。

例如很多API的服务组件以及其他的一些类,都实现了单例获取的方式。分别如:

微博接口调用:

classWeibo_Api

{

protectedstatic$_instance=null;

publicstaticfunctiongetInstance()

{

if(!isset(self::$_instance)){

self::$_instance=newWeibo_Api();

}

returnself::$_instance;

}

//....

}

七牛云存储接口调用:

classQiniu_Api{

privatestatic$_instance=null;//实例对象

publicstaticfunctiongetInstance()

{

if(self::$_instance===null){

self::$_instance=newQiniu_Api();

}

returnself::$_instance;

}

}

QQ开放平台接口调用:

classQQ_Api{

privatestatic$_instance=null;//实例对象

publicstaticfunctiongetInstance()

{

if(self::$_instance===null){

self::$_instance=newQQ_Api();

}

returnself::$_instance;

}

}

如果使用DI对上面这些服务进行管理,则上面三个类乃至其他的类对于单例这块的代码都可以忽略不写。注册代码如下:

$di->sStockApi='Weibo_Api';

$di->sDioAopi='Qiniu_Api';

$di->sShopApi='QQ_Api';

上面是通过类名来进行延迟加载,但需要各个类提供public的无参数的构造函数。如果各个服务需要进行初始化,可以将初始化的工作放置在onInitialize()函数内,DI在对类实例化时会回调此函数进行初始化。

(2)统一资源注册,便于后期维护管理

这里引入DI,更多是为了“一处创建,多处使用”, 而不是各自创建,各自使用。

创建和使用分离

考虑以下场景:假设有这样的业务数据需要缓存机制,所以可注册一个实现缓存机制的实例:

$di->set('cache',newFileCache());

然后提供给多个客户端使用:

$di['cache']->set('indexHtml',$indexContent);//缓存页面

$di['cache']->set('config',$config);//缓存公共配置

$di['cache']->set('artistList',$artistList);//缓存数据

当需要切换到MC或者Redis缓存或者多层缓存时,只需要修改对缓存机制的注入即可,如:

$di->set('cache',newRedisCache());

依赖注入的一个很大的优势就在于可以推迟决策,当需要用到某个对象时,才对其实例化。可以让开发人员在一开始时不必要关注过多的细节实现,同时也给后期的扩展和维护带来极大的方便。

再上一层,假设未来我们需要更高级的缓存服务,那么我们可以在不影响客户端使用的情况下,轻松升级。

未来的可配置化的多级缓存策略

以下是一个模拟的使用场景,但依然对现在的项目有一定的帮助。假设我们现在有一个MC集群的缓存且引入了DI,使用如下:

//初始化

$di=Core_DI::one();

$di->cache=newMemcache();

$di->cache->connect('localhost',11211);

//不同文件的多处使用...

echo$di->cache->get('key');

echo$di->cache->get('key2');

echo$di->cache->get('key3');

...

假设现在发现一层缓存存在穿透情况,为保证服务器的稳定性,我们已开发实现了多层缓存策略,并且可以通过简单配置即可实现,只需要对DI容器里面的cache实例进行升级,其他客户端的调用即可马上享受到缓存升级的优质服务。升级涉及改动的代码如下:

//初始化

$di=newCore_DI();

$di->cache=function(){

$ultraFastFrontend=newDataFrontend(array(

"lifetime"=>3600

));

$fastFrontend=newDataFrontend(array(

"lifetime"=>86400

));

$slowFrontend=newDataFrontend(array(

"lifetime"=>604800

));

returnnewMultiple(array(

newApcCache($ultraFastFrontend,array(

"prefix"=>'cache',)),newMemcacheCache($fastFrontend,"host"=>"localhost","port"=>"11211"

)),newFileCache($slowFrontend,"cacheDir"=>"../app/cache/"

))

));

};

备注:关于多级缓存策略,后续会提供源代码和重用库,或者读者提供 (_)。

(3)延迟式加载,提高性能

延迟加载可以通过DI中的类名初始化、匿名函数和参数配置(未实现)三种方式来实现。

延迟加载有时候是非常有必要的,如在初始化项目 的配置时,随着配置项的数据增加,服务器的性能也将逐渐受到影响,因为配置的内容可能是硬编码,可能来自于数据库,甚至需要通过接口从后台调用获取, 特别当很多配置项不需要使用时。而此时,支持延时加载将可以达到很好的优化,而不用担心在需要使用的时候忘记了初始化。从而很好的提高服务器性能,提高响 应速度。

如对一些耗时的资源先进行匿名函数的初始化:

$di['hightResource']=function(){

//获取返回耗性能的资源

//return$resource;

}

(4)以优雅的方式取代滥用的全局变量

在我看来,PHP里面是不应该使用全局变量(global和$_GLOBALS),更不应该到处使用。

用了DI来管理,即可这样注册:

$di->set('debug',true);

然后这样使用:

$debug=$di->get('debug');

也许有人会想:仅仅是换个地方存放变量而已吗?其实是换一种思想使用资源。

以此延伸,DI还可用于改善优化另外两个地方:通过include文件途径对变量的使用和变量的多层传递。

变量的多层传递,通俗来说就是漂洋过海的变量。

2.11.5 DI思想的来源与推荐参考

phalapi可以依赖注入么_PhalApi:[2.11] 核心思想:DI依赖注入 让资源更可控相关推荐

  1. Spring DI(依赖注入)注解篇

    1 课程内容介绍 我之前写的的一篇博客Spring核心功能DI(依赖注入)xml篇主要介绍了如何通过配置xml的方式来实现依赖注入,今天我们来介绍如何通过注解方式完成我们的依赖注入操作. 2 注入基本 ...

  2. phalapi可以依赖注入么_phalapi-进阶篇2(DI依赖注入和单例模式)

    phalapi-进阶篇2(DI依赖注入和单例模式) 前言 先在这里感谢phalapi框架创始人@dogstar,为我们提供了这样一个优秀的开源框架. 离上一次更新过去了快两周,在其中编写了一个关于DB ...

  3. phalapi可以依赖注入么_[7.8]-phalapi-进阶篇2(DI依赖注入和单例模式) | PhalApi(π框架) - PHP轻量级开源接口框架...

    phalapi-进阶篇2(DI依赖注入和单例模式) 前言 先在这里感谢phalapi框架创始人@dogstar,为我们提供了这样一个优秀的开源框架. 离上一次更新过去了快两周,在其中编写了一个关于DB ...

  4. DI 依赖注入实现原理

    深度理解依赖注入(Dependence Injection) 前面的话:提到依赖注入,大家都会想到老马那篇经典的文章.其实,本文就是相当于对那篇文章的解读.所以,如果您对原文已经有了非常深刻的理解,完 ...

  5. 【Java从0到架构师】Spring - IoC 控制反转、DI 依赖注入

    IoC 控制反转.DI 依赖注入 Spring 简介 Spring 基本使用 - IoC 容器 依赖注入 (Dependency Injection) 基于 setter 的注入 - 自定义对象 be ...

  6. 什么是IOC(控制反转)、DI(依赖注入)举个形象的例子通俗易懂

    更多免费教学文章请关注这里 学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清 ...

  7. Spring-初识Spring框架-IOC控制反转(DI依赖注入)

    ---恢复内容开始--- IOC :控制反转 (DI:依赖注入) 使用ioc模式开发 实体类必须有无参构造方法 1.搭建Spring环境 下载jar http://maven.springframew ...

  8. 什么是IOC(控制反转)、DI(依赖注入)

    原文地址(摘要了部分内容):https://blog.csdn.net/qq_22654611/article/details/52606960/ 学习过Spring框架的人一定都会听过Spring的 ...

  9. 手写Spring DI依赖注入,嘿,你的益达!

    手写DI 提前实例化单例Bean DI分析 DI的实现 构造参数依赖 一:定义分析 二:定义一个类BeanReference 三:BeanDefinition接口及其实现类 四:DefaultBean ...

  10. 详解spring的IOC控制反转和DI依赖注入

    转载 详解spring的IOC控制反转和DI依赖注入 2018-06-05 15:45:34 jiuqijack 阅读数 2945 文章标签: spring IOC控制反转 DI依赖注入 更多 分类专 ...

最新文章

  1. SQL Server里Grouping Sets的威力
  2. 从一个工程师到管理员的经验分享
  3. Anaconda 安装 Python 库(MySQLdb)的方法
  4. slack 使用说明_我如何使用Node和Botkit构建HR Slack Bot
  5. SQL----常用函数
  6. [论文翻译] Class-incremental learning: survey and performance evaluation on image classification
  7. Qt多线程之QMutex
  8. Vue常用特性~非常详细哦,带源码资料
  9. spark TF-IDF入门
  10. C++设计模式10--命令模式(一)--降低请求发送者与接收者耦合
  11. 三维人体姿态估计年度进展综述(周晓巍教授)
  12. 软件测试与软件调试的区别
  13. 给视频局部添加马赛克,怎么调整马赛克位置
  14. 树莓派外接扩展板的的测试
  15. CSS学习笔记 10.字体
  16. 昂达b450s 内存超频3200,xmp设置教程
  17. 支持nfc的android手机型号,NFC手机有哪些 2017支持NFC功能的手机推荐
  18. 口红微商怎么引流?微商卖口红需要注意什么?
  19. Sailfish应用开发入门(一)Windows 安装Sailfish,创建第一个Sailfish APP
  20. JAVA毕业设计Web美食网站设计计算机源码+lw文档+系统+调试部署+数据库

热门文章

  1. js闭包循环原因_「js基础」JavaScript入门,难不难你来说
  2. Easy Algorithms系列——详解递归与分治
  3. 初中生学python还是java_当你在纠结学Python还是Java时,大二学生已经开始造编程语言了!...
  4. qs计算机圣安排名,2020年QS世界大学排名圣安德鲁斯大学排名第100
  5. 【重磅】DeepMind开源史上最全强化学习框架OpenSpiel(附安装方法)
  6. java创作一个椭圆类_椭圆类——3 (类的复杂设计)
  7. java中nextToken,Java StringTokenizer nextToken()用法及代碼示例
  8. DirectX大作业——3D场景地图
  9. 年审是当月还是当天_车辆年检可以在到期当月进行吗
  10. 设备树使用手册【转】