簡體   English   中英

在PHP中尋找一種優雅的方式來加載依賴項/服務/配置?

[英]Searching for an elegant way in PHP for loading dependencies/services/configuration?

我正在構建一個MVC PHP框架,我想知道哪種最佳方法可以在我的類(無論是其他類還是純配置)中加載所需的內容。

直到今天,我一直使用單例,注冊表和最近的依賴項注入容器。 盡管許多人聲稱DI是必經之路,但在我看來,這只是將組件之間的耦合問題轉移到另一個地方。

Singletons引入了全局狀態,registry引入了緊密耦合,而DI引入了……好,非常復雜。 我仍然很困惑,找不到找到彼此聯系的正確方法。

同時,我想出了一個自定義解決方案。 實際上,這不是解決方案,它只是從我的代碼中抽象出了服務加載的實現。

我用_load_service和_load_config方法構建了一個抽象類,框架的所有組件都對其進行了擴展,以加載其他服務或配置。

abstract class Base_Component {
    function _load_service($service) {
        // could be either
        return DI_container::getInstance()->$service;

        // or
        $class = '\services\\'.$service;
        return new $class;

        // or other implementation
    }
}

現在,僅在一個位置(基類)中實現了加載它們的實現,因此至少我在組件中擺脫了如下代碼行:

$database = new Database(Registry::getInstance()->load('db_config'));

要么

$database = DI_container::getInstance()->database;

現在,如果想要一個數據庫實例,我可以這樣做

$database = $this->_load_service('database');

並且可以在單個類方法中輕松更改服務加載程序,容器,注冊表或其他任何東西的實現,而無需搜索我的所有代碼即可將調用更改為我以前使用的任何容器實現。

但是正如我所說,我什至還不確定要使用哪種方法來加載類和配置。

您對此有何看法?

為什么要重新發明輪子? Pimple用作DI容器,並從其文檔中學習如何使用它。

或者,以Silex微框架為基礎來創建自己的框架。 它擴展了Pimple功能,因此您可以使用依賴項注入。

要回答您的問題,這是如何在不將類與其耦合的情況下使用DI:

interface ContainerInterface {
    public function getService($service_name);
    public function registerService($service_name,Closure $service_definition);
}

class Application {
    public function __construct(ContainerInterface $container) {
        $this->container= $container;
    }

    public function run() {
        // very simple to use!
        $this->container->getService('db')->someDatabaseQuery();
    }
}

$c = new My_DI_Container;

// Service definitions could be in a separate file
$c->registerService('db',function() { return new Database('some config'); });

// Then you inject your DI container into the objects that need it
$app = new Application($c);
$app->run(); // or whatever

這樣,DI容器將解耦,將來您可以使用其他實現。 唯一的要求是它實現ContainerInterface。

請注意,容器對象是被推動而不是被拉動的。 避免使用單例。 要獲取/設置單實例對象,請使用容器(這是它的責任)。 要獲取容器實例,只需將其通過構造函數推送即可。

回答您的問題; 看一下PHP 自動加載 通過自動加載來注冊類使您不必在任何地方都放置需求/包含,這確實對RAD(快速應用程序開發)產生積極影響。

我的想法:

為完成如此艱巨的任務而感到榮譽,您的方法似乎基於諸如單例和工廠之類的良好實踐。

我不在乎依賴注入。 OOP基於封裝,將一個對象注入到另一個對象imo中會破壞這種封裝。 當您將一個對象注入另一個對象時,目標對象必須“相信”與注入的對象無關的任何內容,否則可能會出現異常行為。

考慮對類進行名稱命名(而不是PHP名稱),但要像Zend一樣為您的框架加上前綴Zend_,這將有所幫助,以便您可以注冊名稱空間,然后在調用類時,自動加載器將確保加載正確的類。 。 這就是Zend_Framework的工作方式。 有關詳細信息,請查看Zend_Loader_Autoloader 實際上,Symfony框架更進一步。 在第一個請求期間,它將遍歷所有已知位置以查找類文件,然后將構建一個類和文件路徑的數組,然后將該數組保存到文件中(文件緩存),因此后續請求不會相同的開銷。 需要為您的框架考慮的東西。

就配置文件而言,Symfony使用YAML文件,我發現它非常靈活。 您甚至可以包含PHP代碼以提高靈活性。 Symfony提供了易於使用的獨立YAML解析器 您可以通過添加緩存層和緩存已解析的YAML文件來提高性能,從而不必為每個請求都解析文件。

我假設您是在ORM之上構建您的框架。 我的建議不是針對特定版本的ORM的任何功能,否則您的框架將與該版本耦合,並且您將必須同時升級ORM和該框架。

我建議在其他框架下進行深入研究,看看是否可以選擇每個框架中的最佳框架。 從而形成一個堅實,易於使用的框架。

暫無
暫無

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

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