2013-06-05 62 views
2

我正在開發一個用於教育目的的PHP框架。自從我開始學習以來,我學到了很多東西。php依賴注入容器

我已決定如何處理依賴關係。我創建了一個簡單的DI容器。


第一問題不是關於DI容器本身,而是如何注入所創建外(DI容器之前)對象。

問:在這個例子中:我打電話給container->manualAdd('_logger', $logger);。有沒有另外一種方法來完成這個?我打破DI容器的想法嗎?


第二問題是關於掛鉤的功能。所以當在自舉中所有的對象都被實例化時,它自己的對象現在可以開始運行。

問:在這個例子中:我創建了一個EventDispatcher。無論誰需要在doneBuildbeforeTerminate上做點什麼,都會注入BootstrapEventDispatcher。有沒有另一種方法來做到這一點?

我開始覺得EventDispatcher是矯枉過正(僅適用於bootstrap),並可能實施類似:CodeIgniter:Hooks

任何幫助表示讚賞。

實施例的自舉(僞代碼):一個xml的

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

實施例:

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

你看任何現有的DIC的實現,例如疙瘩? (http://pimple.sensiolabs.org/)可能會給你一些想法。記錄器和調度器應該在需要時由容器本身創建。 Silex(http://silex.sensiolabs.org/doc/services.html)是一個微型框架,其主應用程序類擴展了Pimple。它可能會給你一些關於如何引導事物的想法。 – Cerad

+0

我在看Silex並瞭解他們是如何做到的。謝謝! – OsakaHQ

回答

2

從我的Silex/Symfony2的理解,是否沒有「神奇的方式」來做這些事情。

對於我的第一個問題:允許添加在容器之前創建的對象。

在Symfony2中,在Kernel:initializeContainer函數中,Kernel將自身添加到容器中($this->container->set('kernel', $this);),稍後在xml文件中,服務注入內核(<argument id="kernel" type="service" />)。

在Silex中,Application:__construct函數創建並向容器添加對象。 Application將自身注入到ServiceProviders,因此這些提供程序可以將依賴關係注入其對象並將它們添加到容器中。

$container->manualAdd('_logger', $logger);是正確的


對於我第二問題:要看我要如何處理它。只要kernel.terminate += kernelTerminate

0.2此事件(:我想出了3個選項:

0.1對於C#-event狀,Kernel加入到容器中:

在ComplexClass EventDispatcher類不需要在xml文件中創建的依賴關係)

​​

<!-- in file.xml:ComplexClass !--> 
<argument id="_kernel.dispatcher" type="service" /> 

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