Skip to content

Commit d3b5d60

Browse files
committed
Type-specifying extension for ReflectionClass::isSubclassOf()
1 parent f124a45 commit d3b5d60

File tree

5 files changed

+86
-2
lines changed

5 files changed

+86
-2
lines changed

conf/config.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,11 @@ services:
10241024
tags:
10251025
- phpstan.broker.dynamicFunctionReturnTypeExtension
10261026

1027+
-
1028+
class: PHPStan\Type\Php\ReflectionClassIsSubclassOfTypeSpecifyingExtension
1029+
tags:
1030+
- phpstan.typeSpecifier.methodTypeSpecifyingExtension
1031+
10271032
-
10281033
class: PHPStan\Type\Php\ReplaceFunctionsDynamicReturnTypeExtension
10291034
tags:

src/Testing/TestCase.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -628,8 +628,8 @@ public function createTypeSpecifier(
628628
$printer,
629629
$reflectionProvider,
630630
self::getContainer()->getServicesByTag(TypeSpecifierFactory::FUNCTION_TYPE_SPECIFYING_EXTENSION_TAG),
631-
$methodTypeSpecifyingExtensions,
632-
$staticMethodTypeSpecifyingExtensions
631+
array_merge($methodTypeSpecifyingExtensions, self::getContainer()->getServicesByTag(TypeSpecifierFactory::METHOD_TYPE_SPECIFYING_EXTENSION_TAG)),
632+
array_merge($staticMethodTypeSpecifyingExtensions, self::getContainer()->getServicesByTag(TypeSpecifierFactory::STATIC_METHOD_TYPE_SPECIFYING_EXTENSION_TAG)),
633633
);
634634
}
635635

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Php;
4+
5+
use PhpParser\Node\Expr\MethodCall;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Analyser\SpecifiedTypes;
8+
use PHPStan\Analyser\TypeSpecifier;
9+
use PHPStan\Analyser\TypeSpecifierAwareExtension;
10+
use PHPStan\Analyser\TypeSpecifierContext;
11+
use PHPStan\Reflection\MethodReflection;
12+
use PHPStan\Type\Constant\ConstantStringType;
13+
use PHPStan\Type\Generic\GenericObjectType;
14+
use PHPStan\Type\MethodTypeSpecifyingExtension;
15+
use PHPStan\Type\ObjectType;
16+
17+
class ReflectionClassIsSubclassOfTypeSpecifyingExtension implements MethodTypeSpecifyingExtension, TypeSpecifierAwareExtension
18+
{
19+
20+
private TypeSpecifier $typeSpecifier;
21+
22+
public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void
23+
{
24+
$this->typeSpecifier = $typeSpecifier;
25+
}
26+
27+
public function getClass(): string
28+
{
29+
return \ReflectionClass::class;
30+
}
31+
32+
public function isMethodSupported(MethodReflection $methodReflection, MethodCall $node, TypeSpecifierContext $context): bool
33+
{
34+
return $methodReflection->getName() === 'isSubclassOf'
35+
&& isset($node->args[0])
36+
&& $context->true();
37+
}
38+
39+
public function specifyTypes(MethodReflection $methodReflection, MethodCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
40+
{
41+
$valueType = $scope->getType($node->args[0]->value);
42+
if (!$valueType instanceof ConstantStringType) {
43+
return new SpecifiedTypes([], []);
44+
}
45+
46+
return $this->typeSpecifier->create(
47+
$node->var,
48+
new GenericObjectType(\ReflectionClass::class, [
49+
new ObjectType($valueType->getValue()),
50+
]),
51+
$context
52+
);
53+
}
54+
55+
}

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10892,6 +10892,11 @@ public function dataBug4573(): array
1089210892
return $this->gatherAssertTypes(__DIR__ . '/data/bug-4573.php');
1089310893
}
1089410894

10895+
public function dataBug4577(): array
10896+
{
10897+
return $this->gatherAssertTypes(__DIR__ . '/data/bug-4577.php');
10898+
}
10899+
1089510900
/**
1089610901
* @param string $file
1089710902
* @return array<string, mixed[]>
@@ -11132,6 +11137,7 @@ private function gatherAssertTypes(string $file): array
1113211137
* @dataProvider dataBug2112
1113311138
* @dataProvider dataArrayMapClosure
1113411139
* @dataProvider dataBug4573
11140+
* @dataProvider dataBug4577
1113511141
* @param string $assertType
1113611142
* @param string $file
1113711143
* @param mixed ...$args
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Bug4577;
4+
5+
use function PHPStan\Analyser\assertType;
6+
7+
class Test
8+
{
9+
10+
public function test(\ReflectionClass $refClass): void
11+
{
12+
if ($refClass->isSubclassOf(Test::class)) {
13+
$instance = $refClass->newInstance();
14+
assertType(Test::class, $instance);
15+
}
16+
}
17+
18+
}

0 commit comments

Comments
 (0)