我正在构建一个MVC PHP框架,我想知道哪些是加载我需要的类的最佳实践,无论是其他类还是普通配置。
直到今天,我一直在使用单例、注册表和依赖注入容器。虽然许多人声称DI是正确的选择,但在我看来,它只是把组件之间的耦合问题转移到了另一个地方。
singleton引入全局状态,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');
和服务加载器、容器、注册表等的实现都可以在单个类方法中轻松更改,而无需搜索所有代码来更改对之前使用的容器实现的调用。
但是正如我所说的,我甚至不确定我将使用什么方法来加载类和配置。
你的意见是什么?
为什么要重新发明轮子?使用ple作为您的DI容器,并从它的文档中学习如何使用它。
或者,使用Silex微框架作为基础来创建您自己的框架。它扩展了ple的功能,所以你可以使用依赖注入。回答你的问题,这是你如何使用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的自动加载。通过自动加载注册类,这样你就不必把require/includes放到任何地方,这对RAD(快速应用程序开发)确实有积极的影响。
我的想法:
为尝试这样一个艰巨的任务而喝彩,你的方法似乎是基于良好的实践,如单例和工厂。
我不关心依赖注入。OOP是基于封装的,在我看来,将一个对象注入另一个对象会打破这种封装。当你将一个对象注入另一个对象时,目标对象必须"相信"被注入对象没有任何变化,否则你可能会得到不寻常的行为。
考虑类的名称间距(不是PHP的名称间距,而是像Zend那样给框架加上前缀Zend_),这将有助于注册命名空间,然后当调用类时,自动加载器将确保加载正确的类。Zend_Framework就是这样工作的。具体请查看Zend_Loader_Autoloader。Symfony框架实际上更进一步;在第一次请求期间,它将遍历所有已知位置查找类文件,然后构建一个类数组和文件路径,然后将该数组保存到文件(文件缓存),因此后续请求不会有相同的开销。为你的框架考虑一些东西。
就配置文件而言,Symfony使用YAML文件,我发现它非常灵活。您甚至可以包含PHP代码以增加灵活性。Symfony提供了一个易于使用的独立YAML解析器。您可以通过添加缓存层和缓存解析的YAML文件来提高性能,这样您就不必为每个请求解析文件。
我假设你是在ORM之上构建你的框架。我的建议是不要升级任何特定于ORM版本的功能,否则您的框架将与该版本耦合,并且您将不得不同时升级ORM和框架。
我建议你看看其他框架,看看你是否能从中挑选出最好的;生成一个可靠的、易于使用的框架。