Symfony依赖注入:最大功能嵌套级别

时间:2019-07-18 17:39:21

标签: php symfony testing dependency-injection

我有一个基于Symfony 4的项目。我想开始基于WebTestCase编写功能测试。我在配置中启用了framework.test: true,并在phpunit中提供了APP_ENV=test

为测试环境构建的服务容器存在问题。我实际上并没有改变APP_ENVframework.test的期望。

当我从测试缓存容器中获取服务时,我最终得到:

Maximum function nesting level of '256' reached, aborting!

在堆栈跟踪中,我可以看到symfony的DI一直试图获取相同的服务:

 ...
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getPanel_Model_EventService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:483
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getDefaultEventRepositoryService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:525
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getDbReachingEventTranslationProviderService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:509
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getCachingEventTranslationProviderService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:541
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getEventContextTakingTranslatorService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:402
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getModelConfiguratorService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:1089
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getPanel_Model_EventService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:483
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getDefaultEventRepositoryService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:525
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getDbReachingEventTranslationProviderService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:509
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getCachingEventTranslationProviderService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:541
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getEventContextTakingTranslatorService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:402
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getModelConfiguratorService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:1089
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getPanel_Model_EventService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:483
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getDefaultEventRepositoryService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:525
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getDbReachingEventTranslationProviderService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:509
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getCachingEventTranslationProviderService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:541
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getEventContextTakingTranslatorService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:402
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getModelConfiguratorService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:1089
 ContainerE6ODQnH\srcApp_KernelTestDebugContainer->getPanel_Model_EventService() at /var/www/html/panel/var/cache/test/ContainerE6ODQnH/srcApp_KernelTestDebugContainer.php:483
...

这很奇怪,因为我的定义中没有循环引用。 APP_ENV=dev中一切正常。

由于某种原因,test容器无法记住$this->services属性中对现有服务的引用。

您知道开发容器和测试容器的构建差异是什么吗?

当我将测试容器的php文件与开发版本进行比较时。他们确实是不同的。没有理由...

更新

以下是在调用循环中生成的服务的示例:

DEV

    protected function getDefaultEventRepositoryService()
    {
        $a = \ClassRegistry::init('Event');

        $this->services['Panel\\Events\\Repository\\DefaultEventRepository'] = $instance = new \Panel\Events\Repository\DefaultEventRepository($a, ($this->services['Panel\\Events\\Repository\\EventMapper'] ?? ($this->services['Panel\\Events\\Repository\\EventMapper'] = new \Panel\Events\Repository\EventMapper())), ($this->privates['timeProvider'] ?? ($this->privates['timeProvider'] = new \Panel\Core\Utils\CurrentTimeProvider())));

        ($this->services['CakeFramework\\ModelConfigurator'] ?? $this->getModelConfiguratorService())->configure($a);

        return $instance;
    }

测试

    protected function getDefaultEventRepositoryService()
    {
        $a = $this->getPanel_Model_EventService();

        if (isset($this->services['Panel\\Events\\Repository\\DefaultEventRepository'])) {
            return $this->services['Panel\\Events\\Repository\\DefaultEventRepository'];
        }

        return $this->services['Panel\\Events\\Repository\\DefaultEventRepository'] = new \Panel\Events\Repository\DefaultEventRepository($a, ($this->services['Panel\\Events\\Repository\\EventMapper'] ?? ($this->services['Panel\\Events\\Repository\\EventMapper'] = new \Panel\Events\Repository\EventMapper())), ($this->privates['timeProvider'] ?? ($this->privates['timeProvider'] = new \Panel\Core\Utils\CurrentTimeProvider())));
    }

如您在上面看到的,有细微的差别。测试环境正在使用服务方法getPanel_Model_EventService。但是在开发环境中,它是直接注入的$a = \ClassRegistry::init('Event');

这导致循环引用,尽管服务定义相同。没有其他service_test文件。知道为什么吗?

1 个答案:

答案 0 :(得分:0)

我调查了这个问题。这是由Symfony的配置器机制和缺乏报告循环依赖关系引起的。

我在公共仓库https://github.com/kamilwylegala/symfony-configurator-circular-dependency

中用代码示例描述了此问题。

改用工厂有助于确定确实存在循环依赖。使用工厂加薪:

PHP Fatal error:  Uncaught Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException: Circular reference detected for service ...