diff --git a/composer.json b/composer.json index 4362ff7..14663f7 100644 --- a/composer.json +++ b/composer.json @@ -1,8 +1,8 @@ { "name": "slam/phpstan-laminas-framework", - "type": "phpstan-extension", "description": "Laminas Framework 3 MVC controller plugin extension for PHPStan.", "license": "MIT", + "type": "phpstan-extension", "authors": [ { "name": "Greg Bell", @@ -19,46 +19,39 @@ ], "require": { "php": ">=8.0", - "phpstan/phpstan": "^1.1.2" - }, - "conflict": { - "laminas/laminas-cache": "<2.13", - "laminas/laminas-filter": "<2.11", - "laminas/laminas-form": "<3.0", - "laminas/laminas-hydrator": "<4.3", - "laminas/laminas-i18n": "<2.11", - "laminas/laminas-inputfilter": "<2.12", - "laminas/laminas-log": "<2.13", - "laminas/laminas-mail": "<2.15", - "laminas/laminas-mvc": "<3.2", - "laminas/laminas-paginator": "<2.10", - "laminas/laminas-validator": "<2.15" + "phpstan/phpstan": "^1.5.6" }, "require-dev": { "laminas/laminas-cache": "^2.13.2", - "laminas/laminas-filter": "^2.12.0", - "laminas/laminas-form": "^3.0.1", + "laminas/laminas-filter": "^2.14.0", + "laminas/laminas-form": "^3.1.1", "laminas/laminas-hydrator": "^4.3.1", - "laminas/laminas-i18n": "^2.11.3", - "laminas/laminas-inputfilter": "^2.12.0", - "laminas/laminas-log": "^2.13.1", - "laminas/laminas-mail": "^2.15.1", - "laminas/laminas-mvc": "^3.3.0", - "laminas/laminas-paginator": "^2.11.0", - "laminas/laminas-validator": "^2.15.0", + "laminas/laminas-i18n": "^2.15.0", + "laminas/laminas-inputfilter": "^2.13.0", + "laminas/laminas-log": "^2.15.0", + "laminas/laminas-mail": "^2.16.0", + "laminas/laminas-mvc": "^3.3.3", + "laminas/laminas-paginator": "^2.12.2", + "laminas/laminas-validator": "^2.17.0", "malukenho/mcbumpface": "^1.1.5", "phpstan/phpstan-deprecation-rules": "^1.0.0", - "phpstan/phpstan-phpunit": "^1.0.0", - "phpunit/phpunit": "^9.5.10", + "phpstan/phpstan-phpunit": "^1.1.0", + "phpunit/phpunit": "^9.5.20", "slam/php-cs-fixer-extensions": "^v3.1.0", "slam/php-debug-r": "^v1.7.0" }, - "extra": { - "phpstan": { - "includes": [ - "extension.neon" - ] - } + "conflict": { + "laminas/laminas-cache": "<2.13", + "laminas/laminas-filter": "<2.14", + "laminas/laminas-form": "<3.1", + "laminas/laminas-hydrator": "<4.3", + "laminas/laminas-i18n": "<2.15", + "laminas/laminas-inputfilter": "<2.13", + "laminas/laminas-log": "<2.15", + "laminas/laminas-mail": "<2.16", + "laminas/laminas-mvc": "<3.3", + "laminas/laminas-paginator": "<2.12", + "laminas/laminas-validator": "<2.17" }, "autoload": { "psr-4": { @@ -69,5 +62,17 @@ "classmap": [ "tests/" ] + }, + "config": { + "allow-plugins": { + "malukenho/mcbumpface": true + } + }, + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + } } } diff --git a/src/Type/Laminas/ControllerPluginClassReflectionExtension.php b/src/Type/Laminas/ControllerPluginClassReflectionExtension.php index 0f14803..199647b 100644 --- a/src/Type/Laminas/ControllerPluginClassReflectionExtension.php +++ b/src/Type/Laminas/ControllerPluginClassReflectionExtension.php @@ -31,7 +31,7 @@ public function getMethod(ClassReflection $classReflection, string $methodName): $plugin = $this->getControllerPluginManager()->get($methodName); \assert(\is_object($plugin)); - $pluginClassName = \get_class($plugin); + $pluginClassName = $plugin::class; if (\is_callable($plugin)) { return $this->reflectionProvider->getClass($pluginClassName)->getNativeMethod('__invoke'); diff --git a/src/Type/Laminas/PluginMethodDynamicReturnTypeExtension/AbstractPluginMethodDynamicReturnTypeExtension.php b/src/Type/Laminas/PluginMethodDynamicReturnTypeExtension/AbstractPluginMethodDynamicReturnTypeExtension.php index 2555d24..211e61c 100644 --- a/src/Type/Laminas/PluginMethodDynamicReturnTypeExtension/AbstractPluginMethodDynamicReturnTypeExtension.php +++ b/src/Type/Laminas/PluginMethodDynamicReturnTypeExtension/AbstractPluginMethodDynamicReturnTypeExtension.php @@ -55,7 +55,7 @@ final public function getTypeFromMethodCall( $pluginInstance = $pluginManager->get($plugin); \assert(\is_object($pluginInstance)); - return new ObjectType(\get_class($pluginInstance)); + return new ObjectType($pluginInstance::class); } if ($argType instanceof StringType) { diff --git a/src/Type/Laminas/ServiceGetterDynamicReturnTypeExtension/AbstractServiceGetterDynamicReturnTypeExtension.php b/src/Type/Laminas/ServiceGetterDynamicReturnTypeExtension/AbstractServiceGetterDynamicReturnTypeExtension.php index 462683c..5873d40 100644 --- a/src/Type/Laminas/ServiceGetterDynamicReturnTypeExtension/AbstractServiceGetterDynamicReturnTypeExtension.php +++ b/src/Type/Laminas/ServiceGetterDynamicReturnTypeExtension/AbstractServiceGetterDynamicReturnTypeExtension.php @@ -47,7 +47,7 @@ final public function getTypeFromMethodCall( $serviceName = $this->methodToServiceMap[$methodReflection->getName()]; $serviceInstance = $serviceManager->get($serviceName); \assert(\is_object($serviceInstance)); - $serviceClass = \get_class($serviceInstance); + $serviceClass = $serviceInstance::class; return new ObjectType($serviceClass); } diff --git a/src/Type/Laminas/ServiceManagerGetDynamicReturnTypeExtension.php b/src/Type/Laminas/ServiceManagerGetDynamicReturnTypeExtension.php index f83df4c..bbcfd02 100644 --- a/src/Type/Laminas/ServiceManagerGetDynamicReturnTypeExtension.php +++ b/src/Type/Laminas/ServiceManagerGetDynamicReturnTypeExtension.php @@ -91,7 +91,17 @@ public function getTypeFromMethodCall( $service = $serviceManager->get($serviceName); if (\is_object($service)) { - return new ObjectServiceManagerType(\get_class($service), $serviceName); + $className = $service::class; + $refClass = new ReflectionClass($service); + if ($refClass->isAnonymous()) { + if (false !== ($parentClass = $refClass->getParentClass())) { + $className = $parentClass->getName(); + } elseif ([] !== ($interfaces = $refClass->getInterfaces())) { + $className = \current($interfaces)->getName(); + } + } + + return new ObjectServiceManagerType($className, $serviceName); } return $scope->getTypeFromValue($service); diff --git a/tests/LaminasIntegration/data/serviceManagerDynamicReturn-0.json b/tests/LaminasIntegration/data/serviceManagerDynamicReturn-0.json index 1d579e6..d128c2a 100644 --- a/tests/LaminasIntegration/data/serviceManagerDynamicReturn-0.json +++ b/tests/LaminasIntegration/data/serviceManagerDynamicReturn-0.json @@ -1,12 +1,12 @@ [ { "message": "The service \"bar\" was not configured in Laminas\\ServiceManager\\ServiceLocatorInterface.", - "line": 24, + "line": 26, "ignorable": true }, { "message": "The service \"foobar\" was not configured in ViewHelperManager nor the class \"foobar\" exists.", - "line": 32, + "line": 34, "ignorable": true } ] \ No newline at end of file diff --git a/tests/LaminasIntegration/data/serviceManagerDynamicReturn-2.json b/tests/LaminasIntegration/data/serviceManagerDynamicReturn-2.json index c546e5f..901685f 100644 --- a/tests/LaminasIntegration/data/serviceManagerDynamicReturn-2.json +++ b/tests/LaminasIntegration/data/serviceManagerDynamicReturn-2.json @@ -1,17 +1,17 @@ [ { "message": "Call to an undefined method LaminasPhpStan\\TestAsset\\CssService::isCssWut().", - "line": 30, + "line": 32, "ignorable": true }, { "message": "Call to an undefined method LaminasPhpStan\\TestAsset\\HeavyService::bar().", - "line": 36, + "line": 38, "ignorable": true }, { "message": "Cannot access property $foo on array.", - "line": 44, + "line": 46, "ignorable": true } ] \ No newline at end of file diff --git a/tests/LaminasIntegration/data/serviceManagerDynamicReturn-3.json b/tests/LaminasIntegration/data/serviceManagerDynamicReturn-3.json index b0b1214..6bf3d59 100644 --- a/tests/LaminasIntegration/data/serviceManagerDynamicReturn-3.json +++ b/tests/LaminasIntegration/data/serviceManagerDynamicReturn-3.json @@ -1,7 +1,7 @@ [ { "message": "Offset 'xyz' does not exist on array{foo: 'bar'}.", - "line": 43, + "line": 45, "ignorable": true } ] \ No newline at end of file diff --git a/tests/LaminasIntegration/data/serviceManagerDynamicReturn.php b/tests/LaminasIntegration/data/serviceManagerDynamicReturn.php index 2f254d4..2590978 100644 --- a/tests/LaminasIntegration/data/serviceManagerDynamicReturn.php +++ b/tests/LaminasIntegration/data/serviceManagerDynamicReturn.php @@ -5,6 +5,8 @@ namespace LaminasPhpStan\Tests\LaminasIntegration\data; use Laminas\ServiceManager\ServiceLocatorInterface; +use LaminasPhpStan\TestAsset\FooInterface; +use LaminasPhpStan\TestAsset\FooService; use LaminasPhpStan\TestAsset\HeavyService; final class serviceManagerDynamicReturn @@ -43,4 +45,15 @@ public function nonObjectServices(): void $var = $config['xyz']; $var = $config->foo; } + + public function testAnonymousClassWithParent(): void + { + $fooProxy = $this->serviceManager->get('foo_proxy'); + (static function (FooService $fooService): void { + })($fooProxy); + + $fooImpl = $this->serviceManager->get('foo_impl'); + (static function (FooInterface $fooService): void { + })($fooImpl); + } } diff --git a/tests/LaminasIntegration/servicemanagerloader.php b/tests/LaminasIntegration/servicemanagerloader.php index 8fbce97..03b0e85 100644 --- a/tests/LaminasIntegration/servicemanagerloader.php +++ b/tests/LaminasIntegration/servicemanagerloader.php @@ -6,6 +6,7 @@ use Laminas\ServiceManager\Factory\InvokableFactory; use LaminasPhpStan\TestAsset\BarService; use LaminasPhpStan\TestAsset\CssService; +use LaminasPhpStan\TestAsset\FooInterface; use LaminasPhpStan\TestAsset\FooService; use LaminasPhpStan\TestAsset\HeavyService; use LaminasPhpStan\TestAsset\Route66; @@ -16,9 +17,9 @@ 'Laminas\Router', 'LaminasPhpStan' => new class() implements ConfigProviderInterface { /** - * @return array|string>>> + * @return array|Closure|string>>> */ - public function getConfig() + public function getConfig(): array { return [ 'service_manager' => [ @@ -32,6 +33,18 @@ public function getConfig() ], 'factories' => [ HeavyService::class => InvokableFactory::class, + 'foo_proxy' => static function (): FooService { + return new class() extends FooService { + }; + }, + 'foo_impl' => static function (): FooInterface { + return new class() implements FooInterface { + public function isFoo(): bool + { + return true; + } + }; + }, ], ], 'controllers' => [ diff --git a/tests/TestAsset/FooInterface.php b/tests/TestAsset/FooInterface.php new file mode 100644 index 0000000..37962b5 --- /dev/null +++ b/tests/TestAsset/FooInterface.php @@ -0,0 +1,8 @@ +