我正在构建一个MVC PHP框架,我想知道哪些是在我的类中加载我需要的最佳实践,无论是其他类还是普通配置。
直到今天我使用了单身人士,注册表和最近的依赖注入容器。 虽然很多人声称DI是要走的路,但在我看来它只是将组件之间的耦合问题转移到另一个地方。
单身人士介绍全球状态,注册表介绍紧密耦合和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');
并且可以在单个类方法中轻松更改服务加载器,容器,注册表或其他任何内容的实现,而无需搜索我的所有代码来更改对之前使用的任何容器实现的调用。
但正如我所说,我甚至不确定我将用于加载类和配置的方法。
你有什么看法?
答案 0 :(得分:1)
为什么重新发明轮子?使用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。
请注意,正在推送容器对象,而不是拉出容器对象。避免使用单身人士。要获取/设置单实例对象,请使用容器(这是它的职责)。要获取容器实例,只需将其推送到构造函数。
答案 1 :(得分:0)
回答你的问题;看看PHP autoloading。通过自动加载注册类使得您无需在任何地方放置require / includes,这确实对RAD(快速应用程序开发)产生了积极影响。
我的想法:
为了尝试这样一项艰巨的任务,你的方法似乎是基于单身人士和工厂等良好做法。
我不关心依赖注入。 OOP基于封装,将一个对象注入另一个,imo,打破封装。将对象注入另一个对象时,目标对象必须“信任”没有关于注入对象的任何内容发生更改,否则您可能会遇到异常行为。
考虑你的类的名称间距(不是PHP名称间距,但是你的框架前缀像Zend一样,Zend_),这将有助于你可以注册一个名称空间,然后当一个类被调用时,自动加载器将确保正确类已加载。这就是Zend_Framework的工作原理。有关具体信息,请查看Zend_Loader_Autoloader。 Symfony框架实际上更进了一步;在第一个请求期间,它将遍历查找类文件的所有已知位置,然后它将构建一个类的数组和文件的路径,然后将数组保存到文件(文件缓存),因此后续请求将不会同样的开销。为您的框架考虑的事情。
就配置文件而言,Symfony使用YAML文件,我发现它非常灵活。您甚至可以包含PHP代码以提高灵活性。 Symfony提供了一个易于使用的独立YAML parser。您可以通过添加缓存层和缓存已解析的YAML文件来提高性能,这样您就不必为每个请求解析文件。
我假设您正在构建ORM之上的框架。我的建议不是针对ORM版本的任何特定功能,否则您的框架将与该版本相结合,您必须同时升级ORM和框架。
我建议在其他框架下查看内幕,看看你是否可以选择最好的每个框架;从而形成一个坚固,易于使用的框架。