Skip to content

Commit 7944d45

Browse files
authored
ServiceManager: handle services as anonymous classes (#32)
1 parent c82c8d2 commit 7944d45

12 files changed

+94
-45
lines changed

composer.json

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"name": "slam/phpstan-laminas-framework",
3-
"type": "phpstan-extension",
43
"description": "Laminas Framework 3 MVC controller plugin extension for PHPStan.",
54
"license": "MIT",
5+
"type": "phpstan-extension",
66
"authors": [
77
{
88
"name": "Greg Bell",
@@ -19,46 +19,39 @@
1919
],
2020
"require": {
2121
"php": ">=8.0",
22-
"phpstan/phpstan": "^1.1.2"
23-
},
24-
"conflict": {
25-
"laminas/laminas-cache": "<2.13",
26-
"laminas/laminas-filter": "<2.11",
27-
"laminas/laminas-form": "<3.0",
28-
"laminas/laminas-hydrator": "<4.3",
29-
"laminas/laminas-i18n": "<2.11",
30-
"laminas/laminas-inputfilter": "<2.12",
31-
"laminas/laminas-log": "<2.13",
32-
"laminas/laminas-mail": "<2.15",
33-
"laminas/laminas-mvc": "<3.2",
34-
"laminas/laminas-paginator": "<2.10",
35-
"laminas/laminas-validator": "<2.15"
22+
"phpstan/phpstan": "^1.5.6"
3623
},
3724
"require-dev": {
3825
"laminas/laminas-cache": "^2.13.2",
39-
"laminas/laminas-filter": "^2.12.0",
40-
"laminas/laminas-form": "^3.0.1",
26+
"laminas/laminas-filter": "^2.14.0",
27+
"laminas/laminas-form": "^3.1.1",
4128
"laminas/laminas-hydrator": "^4.3.1",
42-
"laminas/laminas-i18n": "^2.11.3",
43-
"laminas/laminas-inputfilter": "^2.12.0",
44-
"laminas/laminas-log": "^2.13.1",
45-
"laminas/laminas-mail": "^2.15.1",
46-
"laminas/laminas-mvc": "^3.3.0",
47-
"laminas/laminas-paginator": "^2.11.0",
48-
"laminas/laminas-validator": "^2.15.0",
29+
"laminas/laminas-i18n": "^2.15.0",
30+
"laminas/laminas-inputfilter": "^2.13.0",
31+
"laminas/laminas-log": "^2.15.0",
32+
"laminas/laminas-mail": "^2.16.0",
33+
"laminas/laminas-mvc": "^3.3.3",
34+
"laminas/laminas-paginator": "^2.12.2",
35+
"laminas/laminas-validator": "^2.17.0",
4936
"malukenho/mcbumpface": "^1.1.5",
5037
"phpstan/phpstan-deprecation-rules": "^1.0.0",
51-
"phpstan/phpstan-phpunit": "^1.0.0",
52-
"phpunit/phpunit": "^9.5.10",
38+
"phpstan/phpstan-phpunit": "^1.1.0",
39+
"phpunit/phpunit": "^9.5.20",
5340
"slam/php-cs-fixer-extensions": "^v3.1.0",
5441
"slam/php-debug-r": "^v1.7.0"
5542
},
56-
"extra": {
57-
"phpstan": {
58-
"includes": [
59-
"extension.neon"
60-
]
61-
}
43+
"conflict": {
44+
"laminas/laminas-cache": "<2.13",
45+
"laminas/laminas-filter": "<2.14",
46+
"laminas/laminas-form": "<3.1",
47+
"laminas/laminas-hydrator": "<4.3",
48+
"laminas/laminas-i18n": "<2.15",
49+
"laminas/laminas-inputfilter": "<2.13",
50+
"laminas/laminas-log": "<2.15",
51+
"laminas/laminas-mail": "<2.16",
52+
"laminas/laminas-mvc": "<3.3",
53+
"laminas/laminas-paginator": "<2.12",
54+
"laminas/laminas-validator": "<2.17"
6255
},
6356
"autoload": {
6457
"psr-4": {
@@ -69,5 +62,17 @@
6962
"classmap": [
7063
"tests/"
7164
]
65+
},
66+
"config": {
67+
"allow-plugins": {
68+
"malukenho/mcbumpface": true
69+
}
70+
},
71+
"extra": {
72+
"phpstan": {
73+
"includes": [
74+
"extension.neon"
75+
]
76+
}
7277
}
7378
}

src/Type/Laminas/ControllerPluginClassReflectionExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function getMethod(ClassReflection $classReflection, string $methodName):
3131
$plugin = $this->getControllerPluginManager()->get($methodName);
3232
\assert(\is_object($plugin));
3333

34-
$pluginClassName = \get_class($plugin);
34+
$pluginClassName = $plugin::class;
3535

3636
if (\is_callable($plugin)) {
3737
return $this->reflectionProvider->getClass($pluginClassName)->getNativeMethod('__invoke');

src/Type/Laminas/PluginMethodDynamicReturnTypeExtension/AbstractPluginMethodDynamicReturnTypeExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ final public function getTypeFromMethodCall(
5555
$pluginInstance = $pluginManager->get($plugin);
5656
\assert(\is_object($pluginInstance));
5757

58-
return new ObjectType(\get_class($pluginInstance));
58+
return new ObjectType($pluginInstance::class);
5959
}
6060

6161
if ($argType instanceof StringType) {

src/Type/Laminas/ServiceGetterDynamicReturnTypeExtension/AbstractServiceGetterDynamicReturnTypeExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ final public function getTypeFromMethodCall(
4747
$serviceName = $this->methodToServiceMap[$methodReflection->getName()];
4848
$serviceInstance = $serviceManager->get($serviceName);
4949
\assert(\is_object($serviceInstance));
50-
$serviceClass = \get_class($serviceInstance);
50+
$serviceClass = $serviceInstance::class;
5151

5252
return new ObjectType($serviceClass);
5353
}

src/Type/Laminas/ServiceManagerGetDynamicReturnTypeExtension.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,17 @@ public function getTypeFromMethodCall(
9191

9292
$service = $serviceManager->get($serviceName);
9393
if (\is_object($service)) {
94-
return new ObjectServiceManagerType(\get_class($service), $serviceName);
94+
$className = $service::class;
95+
$refClass = new ReflectionClass($service);
96+
if ($refClass->isAnonymous()) {
97+
if (false !== ($parentClass = $refClass->getParentClass())) {
98+
$className = $parentClass->getName();
99+
} elseif ([] !== ($interfaces = $refClass->getInterfaces())) {
100+
$className = \current($interfaces)->getName();
101+
}
102+
}
103+
104+
return new ObjectServiceManagerType($className, $serviceName);
95105
}
96106

97107
return $scope->getTypeFromValue($service);
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
[
22
{
33
"message": "The service \"bar\" was not configured in Laminas\\ServiceManager\\ServiceLocatorInterface.",
4-
"line": 24,
4+
"line": 26,
55
"ignorable": true
66
},
77
{
88
"message": "The service \"foobar\" was not configured in ViewHelperManager nor the class \"foobar\" exists.",
9-
"line": 32,
9+
"line": 34,
1010
"ignorable": true
1111
}
1212
]
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
[
22
{
33
"message": "Call to an undefined method LaminasPhpStan\\TestAsset\\CssService::isCssWut().",
4-
"line": 30,
4+
"line": 32,
55
"ignorable": true
66
},
77
{
88
"message": "Call to an undefined method LaminasPhpStan\\TestAsset\\HeavyService::bar().",
9-
"line": 36,
9+
"line": 38,
1010
"ignorable": true
1111
},
1212
{
1313
"message": "Cannot access property $foo on array<string, string>.",
14-
"line": 44,
14+
"line": 46,
1515
"ignorable": true
1616
}
1717
]
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[
22
{
33
"message": "Offset 'xyz' does not exist on array{foo: 'bar'}.",
4-
"line": 43,
4+
"line": 45,
55
"ignorable": true
66
}
77
]

tests/LaminasIntegration/data/serviceManagerDynamicReturn.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
namespace LaminasPhpStan\Tests\LaminasIntegration\data;
66

77
use Laminas\ServiceManager\ServiceLocatorInterface;
8+
use LaminasPhpStan\TestAsset\FooInterface;
9+
use LaminasPhpStan\TestAsset\FooService;
810
use LaminasPhpStan\TestAsset\HeavyService;
911

1012
final class serviceManagerDynamicReturn
@@ -43,4 +45,15 @@ public function nonObjectServices(): void
4345
$var = $config['xyz'];
4446
$var = $config->foo;
4547
}
48+
49+
public function testAnonymousClassWithParent(): void
50+
{
51+
$fooProxy = $this->serviceManager->get('foo_proxy');
52+
(static function (FooService $fooService): void {
53+
})($fooProxy);
54+
55+
$fooImpl = $this->serviceManager->get('foo_impl');
56+
(static function (FooInterface $fooService): void {
57+
})($fooImpl);
58+
}
4659
}

tests/LaminasIntegration/servicemanagerloader.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Laminas\ServiceManager\Factory\InvokableFactory;
77
use LaminasPhpStan\TestAsset\BarService;
88
use LaminasPhpStan\TestAsset\CssService;
9+
use LaminasPhpStan\TestAsset\FooInterface;
910
use LaminasPhpStan\TestAsset\FooService;
1011
use LaminasPhpStan\TestAsset\HeavyService;
1112
use LaminasPhpStan\TestAsset\Route66;
@@ -16,9 +17,9 @@
1617
'Laminas\Router',
1718
'LaminasPhpStan' => new class() implements ConfigProviderInterface {
1819
/**
19-
* @return array<string, array<string, array<string, array<string, string>|string>>>
20+
* @return array<string, array<string, array<string, array<string, string>|Closure|string>>>
2021
*/
21-
public function getConfig()
22+
public function getConfig(): array
2223
{
2324
return [
2425
'service_manager' => [
@@ -32,6 +33,18 @@ public function getConfig()
3233
],
3334
'factories' => [
3435
HeavyService::class => InvokableFactory::class,
36+
'foo_proxy' => static function (): FooService {
37+
return new class() extends FooService {
38+
};
39+
},
40+
'foo_impl' => static function (): FooInterface {
41+
return new class() implements FooInterface {
42+
public function isFoo(): bool
43+
{
44+
return true;
45+
}
46+
};
47+
},
3548
],
3649
],
3750
'controllers' => [

0 commit comments

Comments
 (0)