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

Laravel依赖注入(DependencyInjection)概念详解

时间:2023-03-30 01:48:04 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部分:极品飞车依赖注入设计模式非常简单,但很难解释。造成这种现象的主要原因是其他介绍依赖注入的文章废话太多,令人费解。下面我会用一些比较适合PHP的例子来说明。HTTP协议是无状态的。如果我们的web应用需要在请求之间存储用户信息,可以通过COOKIE或者SESSION:$_SESSION['language']='fr';在上面的代码中,我们将语言存储在全局变量$_SESSION中,可以这样获取:$user_language=$_SESSION['language'];只有在OOP开发中才会遇到依赖注入,所以假设我们有一个封装了SESSION的SessionStorage类:会话开始();}functionset($key,$value){$_SESSION[$key]=$value;}functionget($key){return$_SESSION[$key];}//...}和更高级别的用户类:classUser{protected$storage;函数__construct(){$this->storage=newSessionStorage();}functionsetLanguage($language){$this->storage->set('language',$language);}functiongetLanguage(){return$this->storage->get('language');}//...}这两个这个类简单好用:$user=newUser();$user->setLanguage('fr');$user_language=$user->get语言();这个方法看起来很完美,但是不够灵活例如:现在想修改sessioncookie名称(默认是PHPSESSID),怎么办?这时候有很多方法:在User类的SessionStorage构造函数中硬编码sessioncookie名称(Hardcode):}//...}或者在User类之外定义一个常量:classUser{function__construct(){$this->storage=newSessionStorage(SESSION_COOKIE_NAME);}//...}define('SESSION_COOKIE_NAME','SESSION_ID');或者传入会话cookie名称作为User类构造函数的参数:classUser{function__construct($cookieName){$this->storage=newSessionStorage($cookieName);}//...}$user=newUser('SESSION_ID');或者向SessionStorage类添加一个选项数组:}//...}$user=newUser(['cookie_name'=>'SESSION_ID']);上面的方法很糟糕:如果把sessioncookie的名字写死,每次要改名字,都得修改User类使用常量,User类的变化会依赖于常数集。使用参数或选项数组看起来很灵活,但它在构造函数中混合了与用户本身无关的东西图中,通过构造函数将一个外部的SessionStorage实例“注入”到User实例中,而不是在User实例内部创建一个SessionStorage实例,这就是依赖注入classUser{function__construct($storage){$this->storage=$存储;}//...}非常清爽!只需先创建一个SessionStorage实例,然后再创建一个User实例:$storage=newSessionStorage('SESSION_ID');$用户=新用户($存储);这样配置SessionStorage就非常简单了,也很容易将$storage类型替换为UserSimple,不需要修改User类。这样就实现了解耦。依赖注入不限于构造函数:ConstructorInjection:classUser{function__construct($storage){$this->storage=$storage;}//...}SetterInjection:classUser{functionsetSessionStorage($storage){$this->storage=$storage;}//...}属性注入:类用户{public$sessionStorage;}$user->sessionStorage=$storage;根据经验,构造函数注入最适合需要的依赖项,例如example中的案例;Setter注入最适合可选的依赖项,例如缓存对象实例。大多数现代PHP框架现在大量使用依赖注入来提供一组分离但粘合的组件://symfony:构造函数注入示例$dispatcher=newsfEventDispatcher();$storage=newsfMySQLSessionStorage(['database'=>'会话','db_table'=>'会话',]);$user=newsfUser($dispatcher,$storage,['default_culture'=>'en']);//ZendFramework:setter注入示例$transport=newZend_Mail_Transport_Smtp('smtp.gmail.com',['auth'=>'登录','用户名'=>'foo','密码'=>'bar','ssl'=>'ssl','端口'=>465,]);$mailer=newZend_Mail();$mailer->setDefaultTransport($transport);如果你有兴趣了解更多关于依赖注入的知识,我强烈推荐阅读MartinFowlerIntroduction或JeffMoore的PPT。您还可以查看我去年关于依赖注入的演讲,其中详细介绍了本文中讨论的示例。希望本文能让您更好地了解依赖注入,在本系列的下一部分中,我将讨论依赖注入容器。原来的。所有Laravel文章都包含在laravel-tips项目中。