diff --git a/phpstan.neon b/phpstan.neon index 45df5546..a690755c 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -8,4 +8,5 @@ parameters: - */tests/tmp/* - */tests/*/ExampleContainer.php - */tests/*/ExampleController.php + - */tests/*/ExampleServiceSubscriber.php - */tests/*/request_get_content.php diff --git a/src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php b/src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php index 89aa45df..3aef9d3c 100644 --- a/src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php +++ b/src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php @@ -50,6 +50,11 @@ public function processNode(Node $node, Scope $scope): array return []; } + $isServiceSubscriber = (new ObjectType('Symfony\Component\DependencyInjection\ServiceSubscriberInterface'))->isSuperTypeOf($argType); + if ($isServiceSubscriber->yes()) { + return []; + } + $serviceId = ServiceMap::getServiceIdFromNode($node->args[0]->value, $scope); if ($serviceId !== null) { $service = $this->serviceMap->getService($serviceId); diff --git a/tests/Rules/Symfony/ContainerInterfacePrivateServiceRuleTest.php b/tests/Rules/Symfony/ContainerInterfacePrivateServiceRuleTest.php index 944405e7..f6329dc4 100644 --- a/tests/Rules/Symfony/ContainerInterfacePrivateServiceRuleTest.php +++ b/tests/Rules/Symfony/ContainerInterfacePrivateServiceRuleTest.php @@ -29,4 +29,18 @@ public function testGetPrivateService(): void ); } + public function testGetPrivateServiceInServiceSubscriber(): void + { + if (!interface_exists('Symfony\\Component\\DependencyInjection\\ServiceSubscriberInterface')) { + self::markTestSkipped('The test needs Symfony\Component\DependencyInjection\ServiceSubscriberInterface class.'); + } + + $this->analyse( + [ + __DIR__ . '/ExampleServiceSubscriber.php', + ], + [] + ); + } + } diff --git a/tests/Rules/Symfony/ExampleServiceSubscriber.php b/tests/Rules/Symfony/ExampleServiceSubscriber.php new file mode 100644 index 00000000..936f952e --- /dev/null +++ b/tests/Rules/Symfony/ExampleServiceSubscriber.php @@ -0,0 +1,52 @@ +get('private'); + } + + public function privateServiceInTestContainer(): void + { + /** @var \Symfony\Bundle\FrameworkBundle\Test\TestContainer $container */ + $container = doFoo(); + $container->get('private'); + } + + public function unknownService(): void + { + $this->get('unknown'); + } + + public function unknownGuardedServiceInsideContext(): void + { + if ($this->has('unknown')) { // phpcs:ignore + $this->get('unknown'); + } + } + + public function unknownGuardedServiceOutsideOfContext(): void + { + if (!$this->has('unknown')) { + return; + } + $this->get('unknown'); + } + + /** + * @return string[] + */ + public static function getSubscribedServices(): array + { + return [ + 'private' => MyService::class, + ]; + } + +}