依賴注入容器理解
耦合
一個好的程式碼結構設計一定是鬆散耦合的,這也是許多通用設計模式的宗旨,就是把分散在各處的同一個功能的程式碼匯聚在一起,形成一個模組,然後在不同模組之間透過一些細小的、明確的管道進行溝通。
在實務上,不同功能和模組之間的互相依賴是不可避免的,而如何處理好這些依賴之間的關係則是程式碼結構能否變得美好的關鍵。
<?php class User { public function register($user) { // 注册操作 ... // 发送确认邮件 $notify = new Notify(); $notify->sendEmail('register', $user); } } class Notify { public function sendEmail($type, $data) { switch $type { case 'register': // 发送注册确认邮件 $email = new Email($type); $email->send($data); ... } } } class Email { public function send($data) { // 发送邮件 } }
上述程式碼中,三個類別之間逐層依賴,三個類別實例化的順序是User -> Notify -> Email
也就是說我先實例化User類,可能執行了一些程式碼之後再去實例化我需要的其他類,例如Notify,以此類推。
這種依賴會讓我們不得不為了得到需要的依賴而去做的一些準備工作,有時候可能一個new操作還不夠。而這部分工作就是所說的耦合,他會讓一個獨立功能的類別不得不去關心一些和自己的主體功能沒什麼關係的操作。
解除一個類別對其他類別的依賴
要解決這個問題也很簡單,我可以先實例化好Email類,然後再實例化Notify,然後把Email物件當作參數傳給Notify,最後實例化User類,然後把Notify傳進去。這就是所謂的依賴注入,可以看到這個過程中類別實例化的順序完全反過來了,先實例化被依賴的對象,而不是先實例化最終需要的對象,這是控制反轉。
程式碼如下:
<?php $email = new Email(); $notify = new Notify($email); $user = new User($notify);
可以透過建構子來注入需要的依賴,也可以用一些其他的方法。
用容器託管依賴
那又有新的問題,例子中只有三個類別還好,那如果這個User類別依賴Notify來發郵件,依賴Model來存資料庫,依賴redis來緩存,這樣固然把依賴關係轉移到了類別的外部,但還是會導致我只想實例化一下User的時候,卻要手動做很多的準備工作,會讓程式碼混亂。所以這個時候需要一個容器。而這個容器的作用就是替我來管理這些依賴。
<?php // 容器 class Container implements ArrayAccess { protected $values = []; public function offsetGet($offset) { return $this->values[$offset]($this); } public function offsetSet($offset, $value) { $this->values[$offset] = $value; } }
在程式啟動的時候,我們可以在一個地方統一的註冊好一系列的基礎服務。
<?php $container = new Container(); $container['notify'] = function($c) { return new Notify(); }; $container['email'] = function($c) { return new Email(); };
就會變成這樣 就是當User需要Notify的時候,會去向容器要這個類別的對象,那至於Notify再依賴什麼其他的東西,我就不用管了,因為Notify也會去向容器要它自己需要的依賴。所有這些依賴關係的處理就完全託管給容器了,我們既不需要去關心依賴之間的層次關係,也避免了依賴之間的耦合。 要注意的是,依賴注入容器一般只接受一個匿名函數,而不是一個實例化好的對象,匿名函數會告訴容器怎樣去獲得一個對象,這樣可以使得一個服務在被需要的時候才會去實例化<?php
class User
{
public function register($user)
{
// 注册操作
...
// 发送确认邮件
$container('notify')->sendEmail('register', $user);
}
}
class Notify
{
public function sendEmail($type, $data)
{
switch $type {
case 'register':
// 发送注册确认邮件
$email = $container['email'];
$email->send($data);
...
}
}
}
class Email
{
public function send($data)
{
// 发送邮件
}
}
以上是簡單易懂理解PHP依賴注入容器的詳細內容。更多資訊請關注PHP中文網其他相關文章!