From 5061f1fb41f7192cd810ebcad086518e0bf71827 Mon Sep 17 00:00:00 2001 From: Robert Meijers Date: Mon, 29 Apr 2024 08:32:24 +0200 Subject: [PATCH] make creation of ServiceMap and ParameterMap lazy Currently one can not use PHPStans `bootstrapFiles` to create the container (dump) which could then be ready by `symfony.containerXmlPath`. This as the order of initialization results in the `XmlServiceMapFactory` / `XmlParameterMapFactory` `create` methods being called before the `bootstrapFiles` are executed. By making the `ServiceMap` / `ParameterMap` lazy these will only be created when actually used, which is after the `bootstrapFiles` have been executed. --- extension.neon | 4 +-- .../ContainerInterfacePrivateServiceRule.php | 2 +- .../ContainerInterfaceUnknownServiceRule.php | 2 +- src/Symfony/DefaultParameterMap.php | 2 +- src/Symfony/DefaultServiceMap.php | 2 +- src/Symfony/FakeParameterMap.php | 2 +- src/Symfony/FakeServiceMap.php | 2 +- src/Symfony/LazyParameterMap.php | 35 +++++++++++++++++++ src/Symfony/LazyServiceMap.php | 35 +++++++++++++++++++ src/Symfony/ParameterMap.php | 2 +- src/Symfony/ServiceMap.php | 2 +- .../ParameterDynamicReturnTypeExtension.php | 4 +-- .../ServiceDynamicReturnTypeExtension.php | 4 +-- 13 files changed, 84 insertions(+), 14 deletions(-) create mode 100644 src/Symfony/LazyParameterMap.php create mode 100644 src/Symfony/LazyServiceMap.php diff --git a/extension.neon b/extension.neon index 1eb888ab..9ca793f6 100644 --- a/extension.neon +++ b/extension.neon @@ -128,14 +128,14 @@ services: class: PHPStan\Symfony\ServiceMapFactory factory: PHPStan\Symfony\XmlServiceMapFactory - - factory: @symfony.serviceMapFactory::create() + factory: PHPStan\Symfony\LazyServiceMap # parameter map symfony.parameterMapFactory: class: PHPStan\Symfony\ParameterMapFactory factory: PHPStan\Symfony\XmlParameterMapFactory - - factory: @symfony.parameterMapFactory::create() + factory: PHPStan\Symfony\LazyParameterMap # ControllerTrait::get()/has() return type - diff --git a/src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php b/src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php index 5e10c2b8..56c5f0bf 100644 --- a/src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php +++ b/src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php @@ -65,7 +65,7 @@ public function processNode(Node $node, Scope $scope): array return []; } - $serviceId = $this->serviceMap::getServiceIdFromNode($node->getArgs()[0]->value, $scope); + $serviceId = $this->serviceMap->getServiceIdFromNode($node->getArgs()[0]->value, $scope); if ($serviceId !== null) { $service = $this->serviceMap->getService($serviceId); if ($service !== null && !$service->isPublic()) { diff --git a/src/Rules/Symfony/ContainerInterfaceUnknownServiceRule.php b/src/Rules/Symfony/ContainerInterfaceUnknownServiceRule.php index ccc1999e..5e70235c 100644 --- a/src/Rules/Symfony/ContainerInterfaceUnknownServiceRule.php +++ b/src/Rules/Symfony/ContainerInterfaceUnknownServiceRule.php @@ -65,7 +65,7 @@ public function processNode(Node $node, Scope $scope): array return []; } - $serviceId = $this->serviceMap::getServiceIdFromNode($node->getArgs()[0]->value, $scope); + $serviceId = $this->serviceMap->getServiceIdFromNode($node->getArgs()[0]->value, $scope); if ($serviceId !== null) { $service = $this->serviceMap->getService($serviceId); $serviceIdType = $scope->getType($node->getArgs()[0]->value); diff --git a/src/Symfony/DefaultParameterMap.php b/src/Symfony/DefaultParameterMap.php index 26317468..8f394005 100644 --- a/src/Symfony/DefaultParameterMap.php +++ b/src/Symfony/DefaultParameterMap.php @@ -35,7 +35,7 @@ public function getParameter(string $key): ?ParameterDefinition return $this->parameters[$key] ?? null; } - public static function getParameterKeysFromNode(Expr $node, Scope $scope): array + public function getParameterKeysFromNode(Expr $node, Scope $scope): array { $strings = TypeUtils::getConstantStrings($scope->getType($node)); diff --git a/src/Symfony/DefaultServiceMap.php b/src/Symfony/DefaultServiceMap.php index cb8259d2..80011a3f 100644 --- a/src/Symfony/DefaultServiceMap.php +++ b/src/Symfony/DefaultServiceMap.php @@ -34,7 +34,7 @@ public function getService(string $id): ?ServiceDefinition return $this->services[$id] ?? null; } - public static function getServiceIdFromNode(Expr $node, Scope $scope): ?string + public function getServiceIdFromNode(Expr $node, Scope $scope): ?string { $strings = TypeUtils::getConstantStrings($scope->getType($node)); return count($strings) === 1 ? $strings[0]->getValue() : null; diff --git a/src/Symfony/FakeParameterMap.php b/src/Symfony/FakeParameterMap.php index 53acdc3c..039a89b4 100644 --- a/src/Symfony/FakeParameterMap.php +++ b/src/Symfony/FakeParameterMap.php @@ -21,7 +21,7 @@ public function getParameter(string $key): ?ParameterDefinition return null; } - public static function getParameterKeysFromNode(Expr $node, Scope $scope): array + public function getParameterKeysFromNode(Expr $node, Scope $scope): array { return []; } diff --git a/src/Symfony/FakeServiceMap.php b/src/Symfony/FakeServiceMap.php index 88f9edac..cc3642f6 100644 --- a/src/Symfony/FakeServiceMap.php +++ b/src/Symfony/FakeServiceMap.php @@ -21,7 +21,7 @@ public function getService(string $id): ?ServiceDefinition return null; } - public static function getServiceIdFromNode(Expr $node, Scope $scope): ?string + public function getServiceIdFromNode(Expr $node, Scope $scope): ?string { return null; } diff --git a/src/Symfony/LazyParameterMap.php b/src/Symfony/LazyParameterMap.php new file mode 100644 index 00000000..5f5e5140 --- /dev/null +++ b/src/Symfony/LazyParameterMap.php @@ -0,0 +1,35 @@ +factory = $factory; + } + + public function getParameters(): array + { + return ($this->parameterMap ??= $this->factory->create())->getParameters(); + } + + public function getParameter(string $key): ?ParameterDefinition + { + return ($this->parameterMap ??= $this->factory->create())->getParameter($key); + } + + public function getParameterKeysFromNode(Expr $node, Scope $scope): array + { + return ($this->parameterMap ??= $this->factory->create())->getParameterKeysFromNode($node, $scope); + } + +} diff --git a/src/Symfony/LazyServiceMap.php b/src/Symfony/LazyServiceMap.php new file mode 100644 index 00000000..db634c52 --- /dev/null +++ b/src/Symfony/LazyServiceMap.php @@ -0,0 +1,35 @@ +factory = $factory; + } + + public function getServices(): array + { + return ($this->serviceMap ??= $this->factory->create())->getServices(); + } + + public function getService(string $id): ?ServiceDefinition + { + return ($this->serviceMap ??= $this->factory->create())->getService($id); + } + + public function getServiceIdFromNode(Expr $node, Scope $scope): ?string + { + return ($this->serviceMap ??= $this->factory->create())->getServiceIdFromNode($node, $scope); + } + +} diff --git a/src/Symfony/ParameterMap.php b/src/Symfony/ParameterMap.php index ff0f5224..a391c9f1 100644 --- a/src/Symfony/ParameterMap.php +++ b/src/Symfony/ParameterMap.php @@ -18,6 +18,6 @@ public function getParameter(string $key): ?ParameterDefinition; /** * @return array */ - public static function getParameterKeysFromNode(Expr $node, Scope $scope): array; + public function getParameterKeysFromNode(Expr $node, Scope $scope): array; } diff --git a/src/Symfony/ServiceMap.php b/src/Symfony/ServiceMap.php index 6665ede0..ec69c65b 100644 --- a/src/Symfony/ServiceMap.php +++ b/src/Symfony/ServiceMap.php @@ -15,6 +15,6 @@ public function getServices(): array; public function getService(string $id): ?ServiceDefinition; - public static function getServiceIdFromNode(Expr $node, Scope $scope): ?string; + public function getServiceIdFromNode(Expr $node, Scope $scope): ?string; } diff --git a/src/Type/Symfony/ParameterDynamicReturnTypeExtension.php b/src/Type/Symfony/ParameterDynamicReturnTypeExtension.php index 82d3599e..708b7bcb 100644 --- a/src/Type/Symfony/ParameterDynamicReturnTypeExtension.php +++ b/src/Type/Symfony/ParameterDynamicReturnTypeExtension.php @@ -123,7 +123,7 @@ private function getGetTypeFromMethodCall( return $defaultReturnType; } - $parameterKeys = $this->parameterMap::getParameterKeysFromNode($methodCall->getArgs()[0]->value, $scope); + $parameterKeys = $this->parameterMap->getParameterKeysFromNode($methodCall->getArgs()[0]->value, $scope); if ($parameterKeys === []) { return $defaultReturnType; } @@ -222,7 +222,7 @@ private function getHasTypeFromMethodCall( return $defaultReturnType; } - $parameterKeys = $this->parameterMap::getParameterKeysFromNode($methodCall->getArgs()[0]->value, $scope); + $parameterKeys = $this->parameterMap->getParameterKeysFromNode($methodCall->getArgs()[0]->value, $scope); if ($parameterKeys === []) { return $defaultReturnType; } diff --git a/src/Type/Symfony/ServiceDynamicReturnTypeExtension.php b/src/Type/Symfony/ServiceDynamicReturnTypeExtension.php index b0101cf4..5467de98 100644 --- a/src/Type/Symfony/ServiceDynamicReturnTypeExtension.php +++ b/src/Type/Symfony/ServiceDynamicReturnTypeExtension.php @@ -88,7 +88,7 @@ private function getGetTypeFromMethodCall( return $returnType; } - $serviceId = $this->serviceMap::getServiceIdFromNode($methodCall->getArgs()[0]->value, $scope); + $serviceId = $this->serviceMap->getServiceIdFromNode($methodCall->getArgs()[0]->value, $scope); if ($serviceId !== null) { $service = $this->serviceMap->getService($serviceId); if ($service !== null && (!$service->isSynthetic() || $service->getClass() !== null)) { @@ -134,7 +134,7 @@ private function getHasTypeFromMethodCall( return $returnType; } - $serviceId = $this->serviceMap::getServiceIdFromNode($methodCall->getArgs()[0]->value, $scope); + $serviceId = $this->serviceMap->getServiceIdFromNode($methodCall->getArgs()[0]->value, $scope); if ($serviceId !== null) { $service = $this->serviceMap->getService($serviceId); return new ConstantBooleanType($service !== null && $service->isPublic());