【问题标题】:php dependency injection with a container带有容器的php依赖注入
【发布时间】:2013-06-05 18:39:10
【问题描述】:

我正在开发一个用于教育目的的 PHP 框架。自从我开始它以来,我学到了很多东西。

我已经决定如何处理依赖关系。我正在创建一个简单的 DI 容器。


我的第一个问题不是关于 DI 容器本身,而是如何注入在外部创建的对象(在 DI 容器之前)。

问: 在示例中:我打电话给container->manualAdd('_logger', $logger);。还有另一种方法可以做到这一点吗?我打破了 DI Container 的想法吗?


我的第二个问题是关于挂钩函数的。因此,当在 bootstrap 中实例化所有对象时,对象本身就可以开始工作了。

问:在示例中:我正在创建一个 EventDispatcher。无论谁需要在doneBuildbeforeTerminate 上做某事,都会被注入BootstrapEventDispatcher。有没有其他方法可以做到这一点?

我开始认为EventDispatcher 是矫枉过正(仅适用于bootstrap),并且可能实现类似:CodeIgniter:Hooks

感谢任何帮助。

示例引导程序(伪代码):

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');
    }
}

【问题讨论】:

  • 您是否查看过任何现有的 DIC 实现,例如 Pimple? (pimple.sensiolabs.org) 可能会给你一些想法。记录器和调度程序都应该在需要时由容器本身创建。 Silex (silex.sensiolabs.org/doc/services.html) 是一个微框架,其主要应用程序类扩展了 Pimple。它可能会给你一些关于如何引导事物的想法。
  • 我正在研究 Silex 并了解他们是如何做到的。谢谢!

标签: php dependency-injection containers


【解决方案1】:

根据我在 Silex/Symfony2 中的理解,没有“神奇的方式”来做这些事情。

对于我的第一个问题:允许添加在容器之前创建的对象。

在 Symfony2 中,在 Kernel:initializeContainer 函数中,内核将自身添加到容器 ($this-&gt;container-&gt;set('kernel', $this);) 中,然后在 xml 文件中,使用内核 (&lt;argument id="kernel" type="service" /&gt;) 注入服务。

在 Silex 中,Application:__construct 函数创建对象并将其添加到容器中。 Application 将自己注入到 ServiceProviders 中,因此这些提供程序可以将依赖项注入其对象并将它们添加到容器中。

$container-&gt;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
}

引导更新:

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(){
        //...
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-15
    • 2018-09-13
    • 1970-01-01
    • 2013-04-30
    • 2012-11-17
    • 1970-01-01
    • 2016-11-13
    • 1970-01-01
    相关资源
    最近更新 更多