Skip to content

Commit 0a0f429

Browse files
committed
[TASK] Use ReflectionProvider instead of native ReflectionClass
1 parent 051892c commit 0a0f429

File tree

4 files changed

+50
-16
lines changed

4 files changed

+50
-16
lines changed

src/Service/PrototypeServiceDefinitionChecker.php

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,19 @@
55
use PhpParser\Node;
66
use PhpParser\Node\Expr\ClassConstFetch;
77
use PhpParser\Node\Expr\StaticCall;
8+
use PHPStan\Reflection\ReflectionProvider;
89
use SaschaEgerer\PhpstanTypo3\Contract\ServiceDefinitionChecker;
910

1011
final class PrototypeServiceDefinitionChecker implements ServiceDefinitionChecker
1112
{
1213

14+
private ReflectionProvider $reflectionProvider;
15+
16+
public function __construct(ReflectionProvider $reflectionProvider)
17+
{
18+
$this->reflectionProvider = $reflectionProvider;
19+
}
20+
1321
public function isPrototype(ServiceDefinition $serviceDefinition, Node $node): bool
1422
{
1523
return !$serviceDefinition->isHasTags() && !$serviceDefinition->isHasMethodCalls() && $this->canBePrototypeClass($node);
@@ -44,28 +52,30 @@ private function canBePrototypeClass(Node $node): bool
4452
return false;
4553
}
4654

47-
if ($firstArgument->class->isSpecialClassName()) {
48-
return false;
49-
}
50-
51-
/** @var class-string $className */
5255
$className = $firstArgument->class->toString();
5356

54-
$reflection = new \ReflectionClass($className);
57+
if (!$this->reflectionProvider->hasClass($className)) {
58+
return false;
59+
}
5560

56-
$constructorMethod = $reflection->getConstructor();
61+
$classReflection = $this->reflectionProvider->getClass($className);
5762

58-
if ($constructorMethod === null) {
63+
if (!$classReflection->hasConstructor()) {
5964
return true;
6065
}
6166

62-
$constructorParameters = $constructorMethod->getParameters();
67+
$constructorMethod = $classReflection->getConstructor();
68+
69+
$constructorParameters = $constructorMethod->getVariants();
70+
6371
$hasRequiredParameter = false;
6472
foreach ($constructorParameters as $constructorParameter) {
65-
if ($constructorParameter->isOptional()) {
66-
continue;
73+
foreach ($constructorParameter->getParameters() as $parameter) {
74+
if ($parameter->isOptional()) {
75+
continue;
76+
}
77+
$hasRequiredParameter = true;
6778
}
68-
$hasRequiredParameter = true;
6979
}
7080

7181
return $hasRequiredParameter === false;

tests/Unit/Fixtures/NonPrototypeClass.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
final class NonPrototypeClass
66
{
77

8+
/**
9+
* @param string|mixed|null $requiredString
10+
*/
811
public function __construct(string $requiredString)
912
{
1013
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace SaschaEgerer\PhpstanTypo3\Tests\Unit\Fixtures;
4+
5+
final class PrototypeClassWithoutConstructor
6+
{
7+
8+
}

tests/Unit/Service/PrototypeServiceDefinitionCheckerTest.php

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44

55
use PhpParser\BuilderFactory;
66
use PhpParser\Node\Expr\StaticCall;
7-
use PHPUnit\Framework\TestCase;
7+
use PHPStan\Testing\PHPStanTestCase;
88
use SaschaEgerer\PhpstanTypo3\Service\PrototypeServiceDefinitionChecker;
99
use SaschaEgerer\PhpstanTypo3\Service\ServiceDefinition;
1010
use SaschaEgerer\PhpstanTypo3\Tests\Unit\Fixtures\NonPrototypeClass;
1111
use SaschaEgerer\PhpstanTypo3\Tests\Unit\Fixtures\PrototypeClass;
12+
use SaschaEgerer\PhpstanTypo3\Tests\Unit\Fixtures\PrototypeClassWithoutConstructor;
1213

13-
final class PrototypeServiceDefinitionCheckerTest extends TestCase
14+
final class PrototypeServiceDefinitionCheckerTest extends PHPStanTestCase
1415
{
1516

1617
private PrototypeServiceDefinitionChecker $subject;
@@ -40,17 +41,22 @@ public static function provideNonPrototypes(): \Generator
4041
public static function providePrototypes(): \Generator
4142
{
4243
$builderFactory = new BuilderFactory();
43-
$prototypeClass = $builderFactory->classConstFetch(PrototypeClass::class, 'class');
44+
$prototypeClass = $builderFactory->classConstFetch(self::class, 'class');
45+
$prototypeClassWithoutConstructor = $builderFactory->classConstFetch(PrototypeClassWithoutConstructor::class, 'class');
4446

4547
yield 'Service definition has no tags, no method calls and class has no required constructor arguments' => [
4648
$builderFactory->staticCall('Foo', 'foo', [$prototypeClass]),
4749
new ServiceDefinition('foo', 'bar', false, false, null, false, false, false),
4850
];
51+
yield 'Service definition has no tags, no method calls and class has no constructor at all' => [
52+
$builderFactory->staticCall('Foo', 'foo', [$prototypeClassWithoutConstructor]),
53+
new ServiceDefinition('foo', 'bar', false, false, null, false, false, false),
54+
];
4955
}
5056

5157
protected function setUp(): void
5258
{
53-
$this->subject = new PrototypeServiceDefinitionChecker();
59+
$this->subject = self::getContainer()->getByType(PrototypeServiceDefinitionChecker::class);
5460
}
5561

5662
/**
@@ -69,4 +75,11 @@ public function testIsPrototypeIsFalse(StaticCall $node, ServiceDefinition $serv
6975
self::assertFalse($this->subject->isPrototype($serviceDefinition, $node));
7076
}
7177

78+
public static function getAdditionalConfigFiles(): array
79+
{
80+
return [
81+
__DIR__ . '/../../../extension.neon',
82+
];
83+
}
84+
7285
}

0 commit comments

Comments
 (0)