当前位置: 首页 > 后端技术 > PHP

LaravelContainer(容器)概念详解(下)

时间:2023-03-29 20:06:44 PHP

本文翻译自Symfony作者FabienPotencier的《Dependency Injection in general and the implementation of a Dependency Injection Container in PHP》系列文章。第1部分:什么是依赖注入?第2部分:您需要依赖注入容器吗?第3部分:Symfony服务容器介绍第4部分:Symfony服务容器:使用构建器创建服务第5部分:Symfony服务容器:使用XML或YAML描述服务第6部分:极品飞车专有名词之后会变得难以理解正在翻译成中文,后续文章将采用括号+中文备注的形式。上面我通过一些例子解释了DependencyInjection,本文将继续介绍DependencyInjectionContainer(容器)的概念。首先记住这句话:大多数时候DependencyInjection不需要Container。容器仅在您需要管理一堆具有许多依赖项的不同对象时才有用(例如在框架中)。上面说了,创建一个User对象需要先创建一个SessionStorate对象。这里有一个缺陷。创建对象时,需要提前知道它的所有依赖关系:$storage=newSessionStorage('SESSION_ID');$用户=新用户($存储);以ZendFramework中的Zend_Mail库发送邮件为例:$transport=newZend_Mail_Transport_Smtp('smtp.gmail.com',['auth'=>'login','username'=>'foo','密码'=>'bar','ssl'=>'ssl','端口'=>465,]);$mailer=newZend_Mail();$mailer->setDefaultTransport($transport);请把这个例子看作是一个更大系统的一小部分,因为这个简单的例子当然没有必要使用Container。DependencyInjectionContainer是一个“知道如何实例化和配置对象”的对象(工厂模式的升华)。为了做到这一点,它需要知道构造函数的参数,以及对象之间的关系。下面是一个硬编码的Zend_Mail容器:'=>'bar','ssl'=>'ssl','port'=>465,]);}publicfunctiongetMailer(){$mailer=newZend_Mail();$mailer->setDefaultTransport($this->getMailTransport());返回$mailer;这个Container使用起来非常简单:$container=newContainer();$mailer=$container->getMailer();我们只需要向Container询问mailer对象,而不关心mailer是如何创建的。创建邮件程序对象的“杂务”嵌入在容器中。Container通过getMailTransport()方法自动将Zend_Mail_Transport_Smtp依赖注入到Zend_Mail中。细心的网友可能已经发现,这里的Container已经把一切都写死了。我们可以改进它:classContainer{protected$parameters=array();公共函数__construct(array$parameters=[]){$this->parameters=$parameters;}publicfunctiongetMailTransport(){returnnewZend_Mail_Transport_Smtp('smtp.gmail.com',['auth'=>'login','username'=>$this->parameters['mailer.username'],'password'=>$this->parameters['mailer.password'],'ssl'=>'ssl','port'=>465,]);}publicfunctiongetMailer(){$mailer=newZend_Mail();$mailer->setDefaultTransport($this->getMailTransport());返回$mailer;}}现在您可以随时更改用户名和密码:$container=newContainer(['mailer.username'=>'foo','mailer.password'=>'bar',]);$mailer=$container->getMailer();如果需要更改邮件类,只需将类名作为参数传入即可:classContainer{//...publicfunctiongetMailer(){$class=$this->parameters['mailer.class'];$mailer=new$class();$米ailer->setDefaultTransport($this->getMailTransport());返回$mailer;}}$container=newContainer(['mailer.username'=>'foo','mailer.password'=>'bar','mailer.class'=>'Zend_Mail',]);$mailer=$container->getMailer();如果你想每次都得到相同的邮件程序实例,你可以使用单例模式:classContainer{staticprotected$shared=[];//...publicfunctiongetMailer(){if(isset(self::$shared['mailer'])){returnself::$shared['mailer'];}$class=$this->parameters['mailer.class'];$mailer=new$class();$mailer->setDefaultTransport($this->getMailTransport());returnself::$shared['mailer']=$mailer;}}this包含了DependencyInjectionContainers的基本功能:Container管理对象实例化到配置过程对象本身并不知道自己是Container管理的,对Container一无所知。这就是Container可以管理任何PHP对象的原因。使用DI管理依赖项的对象很棒,但不是必需的。容器实现起来很容易,但是手动维护各种乱七八糟的对象还是很麻烦的。下一章,我将介绍容器在Laravel中的实现。笔者下一章的原文是关于Container在Symfony2中的实现,我将其替换为Laravel。原来的。所有Laravel文章都包含在laravel-tips项目中。