Skip to content

Commit

Permalink
ServiceManager: handle services as anonymous classes (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
Slamdunk authored Apr 20, 2022
1 parent c82c8d2 commit 7944d45
Show file tree
Hide file tree
Showing 12 changed files with 94 additions and 45 deletions.
69 changes: 37 additions & 32 deletions composer.json
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -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": {
Expand All @@ -69,5 +62,17 @@
"classmap": [
"tests/"
]
},
"config": {
"allow-plugins": {
"malukenho/mcbumpface": true
}
},
"extra": {
"phpstan": {
"includes": [
"extension.neon"
]
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
12 changes: 11 additions & 1 deletion src/Type/Laminas/ServiceManagerGetDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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
}
]
Original file line number Diff line number Diff line change
@@ -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<string, string>.",
"line": 44,
"line": 46,
"ignorable": true
}
]
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[
{
"message": "Offset 'xyz' does not exist on array{foo: 'bar'}.",
"line": 43,
"line": 45,
"ignorable": true
}
]
13 changes: 13 additions & 0 deletions tests/LaminasIntegration/data/serviceManagerDynamicReturn.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
}
17 changes: 15 additions & 2 deletions tests/LaminasIntegration/servicemanagerloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -16,9 +17,9 @@
'Laminas\Router',
'LaminasPhpStan' => new class() implements ConfigProviderInterface {
/**
* @return array<string, array<string, array<string, array<string, string>|string>>>
* @return array<string, array<string, array<string, array<string, string>|Closure|string>>>
*/
public function getConfig()
public function getConfig(): array
{
return [
'service_manager' => [
Expand All @@ -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' => [
Expand Down
8 changes: 8 additions & 0 deletions tests/TestAsset/FooInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace LaminasPhpStan\TestAsset;

interface FooInterface
{
public function isFoo(): bool;
}
2 changes: 1 addition & 1 deletion tests/TestAsset/FooService.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace LaminasPhpStan\TestAsset;

final class FooService
class FooService
{
public function isFoo(): bool
{
Expand Down

0 comments on commit 7944d45

Please sign in to comment.