摘要:上文書,創建對象需要先創建對象。創建對象的雜活是嵌入在中的。對象使用來管理依賴關系非常好,但不是必須的。很容易實現,但手工維護各種亂七八糟的對象還是很麻煩。所有文章均已收錄至項目。
本文翻譯自 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 項目。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/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...
閱讀 1111·2021-09-22 16:04
閱讀 1494·2019-08-30 15:43
閱讀 1097·2019-08-29 14:01
閱讀 3438·2019-08-26 12:19
閱讀 3352·2019-08-26 12:15
閱讀 1443·2019-08-26 12:13
閱讀 3264·2019-08-23 17:00
閱讀 1483·2019-08-23 15:38