译文首发于 是否需要使用依赖注入容器?,转载请注明出处。

本文是依赖注入(Depeendency Injection)系列教程的第 2 篇文章,本系列教程主要讲解如何使用 PHP 实现一个轻量级服务容器,教程包括:

术语

Depeendency Injection 译作 依赖注入

Depeendency Injection Container 译作 依赖注入容器

Container 译作 容器

Service Container 译作 服务容器

Session 译作 会话

Object-Oriented 译作 面向对象

mock 译作 模拟

anti-patterns 译作 反模式

hardcoded 译作 硬编码

正文

在上一篇 什么是依赖注入 一文中,我从 Web 项目的角度出发,结合实例讲解了「依赖注入」的具体实现。这一篇文章将谈谈「依赖注入容器」。

首先,表名我的观点:

一般使用「依赖注入」就够了,极少数情况需要使用「依赖注入容器」。

仅当需要管理大量依赖组件的实例时,才能真正体现「依赖注入容器」的价值(比如一个框架)。

如果你还记得 什么是依赖注入 中讲到的例子,在创建 User 实例之前,需要先创建 SessionStorage 实例。其实,这样也没什么不好,只不过您需要在充分了解所有依赖的组件后,才能着手创建对应的实例。

$storage = new SessionStorage('SESSION_ID');

$user = new User($storage);

本篇文章接下来的内容,我们将讨论 PHP 实现类似 Symfony 2 的「依赖注入容器」。我想明确的是,在实现「依赖注入容器」时不涉及 Symfony 相关功能,所以我将使用 Zend 框架示例来说明。

这边不涉及框架之争。我非常感谢 Zend 框架组件,事实上,Symfony 框架使用了许多 Zend 框架中的组件。

Zend Framework 的邮件组件可以轻松处理邮件管理工作,通常我们会使用 PHP 内建的 Mail() 函数发送电子邮件,但这不利于扩展。值得庆幸的是,使用 Zend 的邮件组件通过设置发送对象来修改邮件发送行为非常容易。如何使用 Gmail 帐号作为发送者创建 Zend_Mail 实例并发送一封邮件:

$transport = new Zend_Mail_Transport_Stmp('stmp.gmail.com', array(

'auth' => 'login',

'username' => 'foo',

'password' => 'bar',

'ssl' => 'ssl',

'port' => 465,

));

$mailer = new Zend_Mail();

$mailer->setDefaultTransport($transport);

为了使这篇文章简洁,我会使用一些简单的示例。当然,实际项目中对于如此简单的功能,其实没有必要去使用「容器」。那么把这个例子当作由容器管理的众多实例集合中的一个部分就可以了。

「依赖注入容器」是一个知道如何去实例化和配置依赖组件的对象。为了完成这样的工作,「依赖注入容器」需要知道构造函数参数及其对应的依赖组件的对应关系。

下面以硬编码的方式实现一个 Zend_Mail 容器:

class Container

{

public function getMailTransport()

{

return new Zend_Mail_Transport_Stmp('stmp.gmail.com', array(

'auth' => 'login',

'username' => 'foo',

'password' => 'bar',

'ssl' => 'ssl',

'port' => 465,

));

}

public function getMailer()

{

$mailer = new Zend_Mail();

$mailer->setDefaultTransport($this->getMailTransport());

return $mailer;

}

}

使用这个容器类也很简单:

$container = new Container();

$mailer = $container->getMailer();

在使用容器时,我们只需要获取一个 mailer 对象,而无需知道它是如何创建的;有关 mailer 实例创建的所有细节都有这个容器完成。mailer 对象所依赖的传输对象由调用容器的 getMailTransport() 方法自动注入到 mailer 对象中。容器的魔力仅需一个简单的方法调用即可实现。

等等,聪明如你怎么可能没有看出这个容器还不够完美呢 -- 它包含硬编码!因此,我们需要更进一步,将所需要的数据以构造函数的参数形式添加到容器内会更好:

class Container

{

protected $parameters = array();

public function __construct(array $parameters = array())

{

$this->parameters = $parameters;

}

public function getMailTransport()

{

return new Zend_Mail_Transport_Smtp('smtp.gmail.com', array(

'auth' => 'login',

'username' => $this->parameters['mailer.username'],

'password' => $this->parameters['mailer.password'],

'ssl' => 'ssl',

'port' => 465,

));

}

public function getMailer()

{

$mailer = new Zend_Mail();

$mailer->setDefaultTransport($this->getMailTransport());

return $mailer;

}

}

现在可以很容易的修改 Gmail 帐号的用户名和密码了:

$container = new Container(array(

'mailer.username' => 'foo',

'mailer.password' => 'bar',

));

$mailer = $container->getMailer();

如果需要修改这个邮件发送器实现用于测试,还可以将邮件发送器类名作为参数设置到容器:

class Container

{

public function getMailer()

{

$class = $this->parameters['mailer.class'];

$mailer = new $class();

$mailer->setDefaultTransport($this->getMailTransport());

return $mailer;

}

}

$container = new Container(array(

'mailer.username' => 'foo',

'mailer.password' => 'bar',

'mailer.class' => 'Zend_Mail',

));

$mailer = $container->getMailer();

最后,一些优化,每次我想要获取一个邮件发送器实例 $mailer ,都需要创建一个新的实例。因此,可以将容器更改为始终返回相同的对象:

class Container

{

static protected $shared = array();

public function getMailer()

{

if (isset(self::$shared['mailer'])) {

return self::$shared['mailer'];

}

$class = $this->parameters['mailer.class'];

$mailer = new $class();

$mailer->setDefaultTransport($this->getMailTransport());

return self::$shared['mailer'] = $mailer;

}

}

由于引入了一个 $shared 静态成员变量,这样每次调用 getMailer() 方法时,都会返回首次调用时创建的对象实例。

上面我们总结了依赖注入容器需要实现的基本特性。「依赖注入容器」用于管理依赖的对象实例:包含依赖组件的实例化和对组件所需配置的管理。依赖组件并不知道它是由容器管理的,或许依赖组件根本就不知道「依赖注入容器」的存在。这就是为什么容器能够管理任何 PHP 对象的奥秘。甚至,如果这些实例也使用依赖注入来管理自身的依赖,那就更加完美了,但这不是先决条件。

当然,人肉创建和维护容器类会很快成为一场噩梦。但是由于容器的需求非常小,所以很容易实现。接下类的文章,将讨论 Symfony 2 是如何实现「依赖注入容器」的。

python需要依赖注入吗_是否需要使用依赖注入容器?相关推荐

  1. 警告: 检测到依赖关系环:_软件设计:依赖关系

    警告: 检测到依赖关系环: Dependencies in Software Design 软件设计的依存关系 In software development, the idea of depende ...

  2. 依赖倒置原则_设计模式原则之依赖倒置原则

    依赖倒置原则 Dependency Inversion Principle 高层次的类不应该依赖于低层次的类. 两者都应该依赖于抽象接口. 抽象接口不应依赖于具体实现. 具体实现应该依赖于抽象接口. ...

  3. java依赖倒转原则_设计原则之--依赖倒转原则

    [各位博友晚上好,又到了晚上的这个时间,感谢大家一直对Darren博客的支持,希望这篇文章对你有所帮助: 这几天一直在看设计模式:简单工厂模式,策略模式,单一职责原则,开放 [依赖倒转原则又称依赖倒置 ...

  4. sqlmap 注入字典_使用sqlmap进行sql注入

    早就听说BT5sqlmap功能很强大,今天终于下决心拒绝DOTA和苍老师的诱惑,静下心来研究研究这个传说中的sqlmap!由于在虚拟机里面用的蛋疼,我直接在真机上也装了个BT5的系统,嘻嘻··,那感觉 ...

  5. python脚本自动化盲注_三、基于报错型注入和sql盲注的自动化实现

    通过前面payload的构造,不难发现,对于报错型注入和布尔注入(sql盲注)纯手工注入的效率是非常慢的.这些payload语句虽然复杂,但大部分内容都是相同的,因此,一言不合就写了个脚本自动化注入, ...

  6. 依赖注入有点_一文读懂Java控制反转(IOC)与依赖注入(DI)

    要了解控制反转( Inversion of Control ), 我觉得有必要先了解软件设计的一个重要思想:依赖倒置原则(Dependency Inversion Principle ). 什么是依赖 ...

  7. factorybean 代理类不能按照类型注入_彻底搞懂依赖注入(一)Bean实例创建过程

    点击上方"Java知音",选择"置顶公众号" 技术文章第一时间送达! 上一章介绍了Bean的加载过程(IOC初始化过程),加载完成后,紧接着就要用到它的依赖注入 ...

  8. python 检测文件更新失败_依赖错误,检测更新失败,提示这个

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 rick@rick-PC:~$ sudo apt-get update && sudo apt-get dist-upgrade -y 命 ...

  9. python 依赖包管理_依赖管理

    如果我们的项目依赖第三方的jar包,例如commons logging,那么问题来了:commons logging发布的jar包在哪下载? 如果我们还希望依赖log4j,那么使用log4j需要哪些j ...

最新文章

  1. github入门教程
  2. MongoDB索引类型
  3. 大幅广告显示隐藏效果
  4. 用户收货地址h5页面_如何实现H5可视化编辑器的实时预览和真机扫码预览功能?...
  5. VS中添加新项 数据选项卡下没有ADO.NET实体数据模型解决方案
  6. redis之列表字典操作
  7. 【华为二面】2020/3/25_华为第二次技术面试_45分钟
  8. Istio学习笔记-熔断实验
  9. javacc jjtree 写法 以及 jj写法 基本语法 以及应用
  10. 数据库课程设计(民航售票子系统含数据库代码和前端代码)
  11. 全球最强大脑在哪里?阿里小蜜算法团队在寻找
  12. 近几个月Github上最热门的Java项目一览
  13. HEVC intra MPM
  14. Mac电脑的一键切换输入法神器,自动切换输入法!
  15. iphone充电图_为什么我的iPhone无法充电?
  16. win cmd 打开D盘
  17. 香港监管机构收紧加密货币相关法规
  18. libapache2-mod-auth-mysql_軟件包libapache2-mod-auth-mysql不可用
  19. 归并算法经典应用——求解逆序数
  20. java build failed_java - maven build failed:无法在jre或jdk issu中找到Javac编译器

热门文章

  1. 【计算机网络课程设计】TCP协议包自动生成工具【蒙混过关版】
  2. Vue子组件中渲染动态组件无效(第一次无效、第二次有效)
  3. 要不要去柬埔寨工作,很纠结,但是工资我又无法拒绝
  4. 我赢助手小技巧:学会这三招,爆款内容视频完播率提高50%(下)
  5. matlab死亡时间推测实验,死后间隔时间推断的新研究.pdf
  6. 手机上如何传图识字?
  7. Newmark数值分析法matlab程序
  8. php合成视频特效,视频合并加转场效果
  9. Android 桌面应用开发主要代码
  10. javascript:void(0)用法及常见问题解析