繁体   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