Skip to content

Commit 76cbb53

Browse files
committed
Dynamic return type extension for DI Container getByType/createInstance methods
1 parent df6b9c0 commit 76cbb53

File tree

3 files changed

+71
-0
lines changed

3 files changed

+71
-0
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"php": "~7.0",
99
"phpstan/phpstan": "^0.6",
1010
"nette/component-model": "^2.3.0",
11+
"nette/di": "^2.3.0",
1112
"nette/forms": "^2.3.0",
1213
"nette/utils": "^2.3.0"
1314
},

extension.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,8 @@ services:
3333
class: PHPStan\Type\Nette\FormsBaseControlDynamicReturnTypeExtension
3434
tags:
3535
- phpstan.broker.dynamicMethodReturnTypeExtension
36+
37+
-
38+
class: PHPStan\Type\Nette\ServiceLocatorDynamicReturnTypeExtension
39+
tags:
40+
- phpstan.broker.dynamicMethodReturnTypeExtension
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Nette;
4+
5+
use PhpParser\Node\Expr\MethodCall;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Reflection\MethodReflection;
8+
use PHPStan\Type\ObjectType;
9+
use PHPStan\Type\TrueBooleanType;
10+
use PHPStan\Type\Type;
11+
12+
class ServiceLocatorDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension
13+
{
14+
15+
public static function getClass(): string
16+
{
17+
return \Nette\DI\Container::class;
18+
}
19+
20+
public function isMethodSupported(MethodReflection $methodReflection): bool
21+
{
22+
return in_array($methodReflection->getName(), [
23+
'getByType',
24+
'createInstance',
25+
], true);
26+
}
27+
28+
public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type
29+
{
30+
if (count($methodCall->args) === 0) {
31+
return $methodReflection->getReturnType();
32+
}
33+
$arg = $methodCall->args[0]->value;
34+
if (!($arg instanceof \PhpParser\Node\Expr\ClassConstFetch)) {
35+
return $methodReflection->getReturnType();
36+
}
37+
38+
$class = $arg->class;
39+
if (!($class instanceof \PhpParser\Node\Name)) {
40+
return $methodReflection->getReturnType();
41+
}
42+
43+
$class = (string) $class;
44+
45+
if ($class === 'static') {
46+
return $methodReflection->getReturnType();
47+
}
48+
49+
if ($class === 'self') {
50+
$class = $scope->getClass();
51+
}
52+
53+
$isNullable = false;
54+
if (
55+
$methodReflection->getName() === 'getByType'
56+
&& count($methodCall->args) >= 2
57+
&& $scope->getType($methodCall->args[1]->value) instanceof TrueBooleanType
58+
) {
59+
$isNullable = true;
60+
}
61+
62+
return new ObjectType($class, $isNullable);
63+
}
64+
65+
}

0 commit comments

Comments
 (0)