簡體   English   中英

現實生活中的依賴注入

[英]Dependency-injection in real life

我正在構建一個非常小的MVC框架來增加我的PHP知識並挑戰自己。 我已經到了類開始依賴彼此工作的地步。 依賴注入似乎是解決方案,並被一些大框架使用

我在Github上發現了Bucket並且已經搞砸了一段時間才能理解基礎知識。 然而,我無法理解的是,什么時候創建一個容器是合適的?

制作一個大容器,包括可能需要的每個可能的課程,似乎對我來說只是適得其反,我無法想象這是一個好習慣。 這似乎是至少糟糕表現的秘訣。

在替代方案中,即制造多個容器,我仍然不知道如何不再需要那些臭氣熏天的單身人士。

假設我有以下代碼:

$session_container = new bucket_Container();
$session_container->create('Database');
$session_container->create('Database_Sessions');

$log_container = new bucket_Container();
$log_container->create('Database');
$log_container->create('Database_Log');

所以這里我們有兩個容器,或者在這種情況下用於兩個完全不同的用法的 ,它們依賴於Database類。

我的邏輯告訴我,上面的代碼將創建Database -class的兩個獨立實例,這意味着我仍然必須使Database -class成為單例,以確保我的數據庫連接的並發實例沒有發生?

它是否正確?

我不太了解具體的lib,但假設它允許你使用工廠,讓工廠返回相同的實例。

編輯:好的,這只是在Bucket GitHub索引頁面上。

class MyFactory {
  function new_PDO($container) {
    return new PDO("mysql:host=localhost;dbname=addressbook", "root", "secret");
  }
}

$bucket = new bucket_Container(new MyFactory());
$db = $bucket->get('pdo');

所以在你的情況下,你可以簡單地做:

class MyFactory {
   private $pdo;
   function new_Database($container) {
     if($this->pdo){
         return $this->pdo;
     }
     return $this->pdo = new PDO("mysql:host=localhost;dbname=addressbook", "root", "secret");
   }
}
$factory = new MyFactory();

$session_container = new bucket_Container($factory);
$session_container->create('Database_Sessions');

$log_container = new bucket_Container($factory);
$log_container->create('Database_Log');

這樣的事情。 似乎不像火箭科學。

編輯2:我沒有足夠的重復點來評論這個問題(有點傻),但是為了回應你的“模塊性”問題:把容器想象成你應用程序的“粘合劑”。 實際上,如果您有一個大型應用程序,您可能只想在應用程序的隔離部分“粘合”。 這是一個有效的封裝問題。 但即便如此,您仍然需要一個能夠在最高抽象級別處理注入的容器。 如果您只是為應用程序的每個部分創建一個單獨的容器,您最終會得到不必要的實例重復,或者您必須應用另一級別的實例管理,這不會以任何方式改進封裝:您仍然在應用程序的不同部分之間共享實例。

我的建議是在引導級別使用單個容器。 如果您想為應用程序的特定部分(模塊,插件等)添加封裝,請使用“子容器”。 子容器從父容器繼承實例,但父容器對該子容器一無所知(就他而言,他仍然是單身漢;))。 可能是Bucket默認支持這個,我知道其他DI容器。 如果沒有,使用Decorator實現起來非常容易。 想象一下這樣的事情:

class MyContainerType extends bucket_Container {

    private $_parent;
    private $_subject;

    public function  __construct($factory = null, bucket_Container $parent = null){
        $this->_parent = $parent;
        $this->_subject = new bucket_Container($factory);
    }

    public function get($key){
        $value = $this->_subject->get($key);
        if($value){
            return $value;
        }
        return $this->_parent->get($key);
    }
    /**
     * Override and delegation of all other methods
     */
}

制作一個大容器,包括可能需要的每個可能的課程,似乎對我來說只是適得其反,我無法想象這是一個好習慣。 這似乎是至少糟糕表現的秘訣。

反之。 這正是你用di容器做的事情。 容器只會按需實例化對象,因此通過它管理所有單例類幾乎沒有任何開銷。

di的最大問題是區分共享對象(通常認為是單例的東西)和瞬態對象(通過正常應用程序流具有大量實例的對象)。 前者很容易通過di管理。 后者並不適合。 清楚地區分這兩種“對象”可能看起來有點麻煩,但使用di容器確實是非常有益的副作用。

如果您擔心多個同時連接,可以使用mysql_pconnect()或equivelant用於您正在使用的數據庫。 它將檢查連接是否已打開,如果是,則使用現有連接。

至於容器問題,我已經看到它以兩種方式完成,你似乎都知道這兩種方式。 第一種方法是讓框架讀取您的數據庫模式並在每個表之前創建類。 我個人不喜歡這種方法。 Symfony就是這樣做的一個框架(通過使用學說ORM)。

我看到的更優選的方法是擁有一個通用容器,它基本上為你提供了一個表,列和一個動作的sql。 這是codeIgniter采用的方法:

$query = $this->db->get('mytable');
$query = $this->db->get_where('mytable', array('id' => $id), $limit, $offset);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM