我正在开发一个用于教育目的的PHP框架。自从我开始学习以来,我学到了很多东西。
我已经决定了如何处理依赖项。我正在创建一个简单的DI容器。
我的第一个问题不是关于DI容器本身,而是如何注入在外部(在DI容器之前)创建的对象。
问:在示例中:我正在呼叫container->manualAdd('_logger', $logger);
。还有另一种方法来实现这一目标吗?我打破了DI Container的想法吗?
我的第二个问题是关于挂钩功能。因此,当在引导程序中实例化所有对象时,它自身的对象现在可以开始运行了。
问:在示例中:我正在创建一个EventDispatcher。需要在doneBuild
或beforeTerminate
上执行操作的任何人都会注入BootstrapEventDispatcher
。还有另一种方法吗?
我开始认为EventDispatcher
过度(仅适用于bootstrap
),并且可能会实现以下内容:CodeIgniter:Hooks
感谢任何帮助。
示例bootstrap(伪代码):
function bootstrap($file = 'file.xml'){
$logger = new Logger();
$logger->log('bootstrap: init');
$dispatcher = new BootstrapEventDispatcher($logger);
$container = new DIContainer(new ConfigReader($file), $logger);
$container->manualAdd('_logger', $logger);
$container->manualAdd('_bootstrap_event_dispatcher', $dispatcher);
$container->build();
$dispatcher->doneBuild(null, new EventArgs());
$dispatcher->beforeTerminate(null, new EventArgs());
$logger->log('bootstrap: terminate');
}
class DIContainer{
public function build(){
//read xmls and create classes, etc.
$this->logger->log('DIContainer: creating objects: {objects}');
}
}
xml的示例:
<!-- example file.xml !-->
<services>
<service id="simple_class" class="SimpleClass"></service>
<service id="complex_class" class="ComplexClass">
<argument type="service" id="simple_class" /> <!-- dependency injection !-->
<argument type="service" id="_logger" /> <!-- dependency injection !-->
<argument type="service" id="_bootstrap_event_dispatcher" /> <!-- dependency injection !-->
</service>
</services>
ComplexClass示例:
class ComplexClass{
public function __construct(SimpleClass $simpleClass, BootstrapEventDispatcher $dispatcher, Logger $logger){
$this->simpleClass = $simpleClass;
$this->logger = $logger;
$dispatcher->onDoneBuild(array($this, 'onBootstrapDoneBuild'));
}
public function onBootstrapDoneBuild($obj, $args){
//do something.
$this->logger->log('complexclass: did something');
}
}
答案 0 :(得分:2)
根据我对Silex / Symfony2的理解,没有“神奇的方法”来做这些事情。
对于我的第一个问题:允许添加在容器之前创建的对象。
在Symfony2中,在Kernel:initializeContainer
函数中,Kernel将自身添加到容器($this->container->set('kernel', $this);
),稍后,在xml文件中,服务将使用内核(<argument id="kernel" type="service" />
)注入。 / p>
在Silex中,Application:__construct
函数创建对象并将其添加到容器中。 Application
将自身注入ServiceProviders
,因此这些提供程序可以将依赖项注入其对象并将它们添加到容器中。
$container->manualAdd('_logger', $logger);
是正确的。
对于我的第二个问题:取决于我想如何处理它。我想出了3个选项:
.1 对于C#-event-like,Kernel
已添加到容器中:
在ComplexClass中:kernel.terminate += kernelTerminate
.2 EventDispatcher(只要EventDispatcher
类不需要在xml文件中创建的依赖项)
//bootstrap function:
$dispatcher = new KernelEventDispatcher();
$kernel = new Kernel($dispatcher);
$container->manualAdd('_kernel.dispatcher');
<!-- in file.xml:ComplexClass !-->
<argument id="_kernel.dispatcher" type="service" />
.3 创建一个实现接口的对象:(我找不到Runnable
的其他名称)
<!-- in file.xml !-->
<service id="complex_class_runnable" class="ComplexClassRunnable">
<argument type="service" id="complex_class" />
<argument type="service" id="_kernel" />
</service>
//in ComplexClassRunnable
$kernel->addRunnable($this);
//in Kernel
foreach($this->runnables as $runnable){
$runnable->init(); //same for terminate
}
Bootstrap已更新:
function bootstrap($file = 'file.xml'){
$logger = new Logger();
$logger->log('bootstrap: init');
$kernel = new Kernel($logger);
$container = new DIContainer(new ConfigReader($file), $logger);
$container->manualAdd('_kernel', $kernel);
$container->manualAdd('_logger', $logger);
$container->build();
$kernel->boot();
$logger->log('bootstrap: terminate');
}
class DIContainer{
public function build(){
//read xmls and create classes, etc.
$this->logger->log('DIContainer: creating objects: {objects}');
}
}
class Kernel{
public function boot(){
//...
}
}