摘要:上文书,创建对象需要先创建对象。创建对象的杂活是嵌入在中的。对象使用来管理依赖关系非常好,但不是必须的。很容易实现,但手工维护各种乱七八糟的对象还是很麻烦。所有文章均已收录至项目。
本文翻译自 Symfony 作者 Fabien Potencier 的 《Dependency Injection in general and the implementation of a Dependency Injection Container in PHP》 系列文章。
Part 1: What is Dependency Injection?
Part 2: Do you need a Dependency Injection Container?
Part 3: Introduction to the Symfony Service Container
Part 4: Symfony Service Container: Using a Builder to create Services
Part 5: Symfony Service Container: Using XML or YAML to describe Services
Part 6: The Need for Speed
专有名词翻译成中文后会变得不利于理解,后续文章中将改用括号+中文备注的形式。
上文我通过一些示例讲解了 Dependency Injection ,本文将接着介绍 Dependency Injection Containers (容器) 的概念。
首先记住这句话:
大多数时候,Dependency Injection 并不需要 Container。
只有当你需要管理一大堆具有很多依赖关系的不同对象时,Container 才会非常有用(例如框架中)。
上文书,创建 User 对象需要先创建 SessionStorate 对象。这里的有个瑕疵,创建对象时需要提前知道它所有的依赖项:
$storage = new SessionStorage("SESSION_ID"); $user = new User($storage);
以 Zend Framework 中 Zend_Mail 库发送邮件过程为例:
$transport = new Zend_Mail_Transport_Smtp("smtp.gmail.com", [ "auth" => "login", "username" => "foo", "password" => "bar", "ssl" => "ssl", "port" => 465, ]); $mailer = new Zend_Mail(); $mailer->setDefaultTransport($transport);
请把这个例子看做一个大系统中的一小部分,因为这种简单的例子当然没必要用 Container 。
Dependency Injection Container 是一个“知道如何实例化和配置对象”的对象(工厂模式的升华)。为了做到这点,它需要知道构造函数的参数、以及对象之间的关系。
下面是一个写死 Zend_Mail 的 Container:
class Container { public function getMailTransport() { return new Zend_Mail_Transport_Smtp("smtp.gmail.com", [ "auth" => "login", "username" => "foo", "password" => "bar", "ssl" => "ssl", "port" => 465, ]); } public function getMailer() { $mailer = new Zend_Mail(); $mailer->setDefaultTransport($this->getMailTransport()); return $mailer; } }
这个 Container 用起来就相当简单了:
$container = new Container(); $mailer = $container->getMailer();
我们只管向 Container 要 mailer 对象就行,完全不用管 mailer 怎么创建。创建 mailer 对象的“杂活”是嵌入在 Container 中的。
Container 通过 getMailTransport() 方法,把 Zend_Mail_Transport_Smtp 这个依赖自动注入到了 Zend_Mail 中。
细心的网友可能已经发现,这里的 Container 把什么都写死了。我们可以完善一下:
class Container { protected $parameters = array(); public function __construct(array $parameters = []) { $this->parameters = $parameters; } public function getMailTransport() { return new Zend_Mail_Transport_Smtp("smtp.gmail.com", [ "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; } }
现在就可以随时更改 username 和 password 了:
$container = new Container([ "mailer.username" => "foo", "mailer.password" => "bar", ]); $mailer = $container->getMailer();
如果需要更改 mailer 类,把类名也当参数传入就行:
class Container { // ... public function getMailer() { $class = $this->parameters["mailer.class"]; $mailer = new $class(); $mailer->setDefaultTransport($this->getMailTransport()); return $mailer; } } $container = new Container([ "mailer.username" => "foo", "mailer.password" => "bar", "mailer.class" => "Zend_Mail", ]); $mailer = $container->getMailer();
如果想每次获取同一个 mailer 实例,可以用 单例模式:
class Container { static protected $shared = []; // ... 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; } }
这就包含了 Dependency Injection Containers 的基本功能:
Container 管理对象实例化到配置的过程
对象本身不知道自己是由 Container 管理的,对 Container 一无所知。
这就是为什么 Container 能够管理任何 PHP 对象。 对象使用 DI 来管理依赖关系非常好,但不是必须的。
Container 很容易实现,但手工维护各种乱七八糟的对象还是很麻烦。下一章我将介绍 Laravel 中 Container 的实现方式。
作者下一章原文中讲的是 Container 在 Symfony 2 中的实现,我会把它换成 Laravel。
原创。 所有 Laravel 文章均已收录至 laravel-tips 项目。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/25948.html
摘要:意味着依赖被注入进构造函数或者方法如果需要复用实例,可以定义为单例可以用接口或任何名称来代替具体类。技能重写构造函数参数方法允许将附加参数传递给构造函数。 本文大部分翻译自 DAVE JAMES MILLER 的 《Laravel’s Dependency Injection Container in Depth》 。 上文介绍了 Dependency Injection Contai...
摘要:依赖注入并不限于构造函数作为经验,注入最适合必须的依赖关系,比如示例中的情况注入最适合可选依赖关系,比如缓存一个对象实例。 本文翻译自 Symfony 作者 Fabien Potencier 的 《Dependency Injection in general and the implementation of a Dependency Injection Container in P...
摘要:划下重点,服务容器是用于管理类的依赖和执行依赖注入的工具。类的实例化及其依赖的注入,完全由服务容器自动的去完成。 本文首发于 深入剖析 Laravel 服务容器,转载请注明出处。喜欢的朋友不要吝啬你们的赞同,谢谢。 之前在 深度挖掘 Laravel 生命周期 一文中,我们有去探究 Laravel 究竟是如何接收 HTTP 请求,又是如何生成响应并最终呈现给用户的工作原理。 本章将带领大...
摘要:可以为服务提供者的方法设置类型提示。方法将在所有其他服务提供者均已注册之后调用。所有服务提供者都在配置文件中注册。可以选择推迟服务提供者的注册,直到真正需要注册绑定时,这样可以提供应用程序的性能。 本文最早发布于 Rootrl的Blog 导言 Laravel是一款先进的现代化框架,里面有一些概念非常重要。在上手Laravel之前,我认为先弄懂这些概念是很有必要的。你甚至需要重温下PHP...
摘要:依赖注入依赖注入一词是由提出的术语,它是将组件注入到应用程序中的一种行为。就像说的依赖注入是敏捷架构中关键元素。类依赖于,所以我们的代码可能是这样的创建一个这是一种经典的方法,让我们从使用构造函数注入开始。 showImg(https://segmentfault.com/img/remote/1460000018806800); 文章转自:https://learnku.com/la...
阅读 1110·2021-09-22 16:04
阅读 1493·2019-08-30 15:43
阅读 1096·2019-08-29 14:01
阅读 3437·2019-08-26 12:19
阅读 3351·2019-08-26 12:15
阅读 1443·2019-08-26 12:13
阅读 3262·2019-08-23 17:00
阅读 1482·2019-08-23 15:38