Skip to content

Commit e9ee834

Browse files
get_defined_vars() return type contains know variables
1 parent 71d01d6 commit e9ee834

File tree

3 files changed

+108
-0
lines changed

3 files changed

+108
-0
lines changed

conf/config.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1427,6 +1427,11 @@ services:
14271427
tags:
14281428
- phpstan.broker.dynamicFunctionReturnTypeExtension
14291429

1430+
-
1431+
class: PHPStan\Type\Php\GetDefinedVarsFunctionReturnTypeExtension
1432+
tags:
1433+
- phpstan.broker.dynamicFunctionReturnTypeExtension
1434+
14301435
-
14311436
class: PHPStan\Type\Php\GetParentClassDynamicFunctionReturnTypeExtension
14321437
tags:
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Php;
4+
5+
use PhpParser\Node\Expr\FuncCall;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Reflection\FunctionReflection;
8+
use PHPStan\Type\ArrayType;
9+
use PHPStan\Type\Constant\ConstantArrayType;
10+
use PHPStan\Type\Constant\ConstantStringType;
11+
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
12+
use PHPStan\Type\MixedType;
13+
use PHPStan\Type\StringType;
14+
use PHPStan\Type\Type;
15+
use function array_filter;
16+
use function array_map;
17+
use function array_merge;
18+
use function array_values;
19+
use function count;
20+
use function range;
21+
22+
// based on code by @ruudk
23+
final class GetDefinedVarsFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension
24+
{
25+
26+
public function isFunctionSupported(FunctionReflection $functionReflection): bool
27+
{
28+
return $functionReflection->getName() === 'get_defined_vars';
29+
}
30+
31+
public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): Type
32+
{
33+
if ($scope->canAnyVariableExist()) {
34+
return new ArrayType(
35+
new StringType(),
36+
new MixedType(),
37+
);
38+
}
39+
40+
$variables = array_values(array_filter(
41+
$scope->getDefinedVariables(),
42+
static fn ($variable) => $variable !== 'this',
43+
));
44+
45+
$maybeVariables = array_values(
46+
$scope->getMaybeDefinedVariables(),
47+
);
48+
49+
$keys = array_map(
50+
static fn ($variable) => new ConstantStringType($variable),
51+
array_merge($variables, $maybeVariables),
52+
);
53+
54+
$values = array_map(
55+
static fn ($variable) => $scope->getVariableType($variable),
56+
array_merge($variables, $maybeVariables),
57+
);
58+
59+
if ($maybeVariables !== []) {
60+
$maybeIndexes = range(count($variables), count($variables) + count($maybeVariables));
61+
} else {
62+
$maybeIndexes = [];
63+
}
64+
65+
return new ConstantArrayType($keys, $values, [0], $maybeIndexes);
66+
}
67+
68+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace GetDefinedVars;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
function doFoo(int $param) {
8+
$local = "foo";
9+
assertType('array{param: int, local: \'foo\'}', get_defined_vars());
10+
assertType('array{\'param\', \'local\'}', array_keys(get_defined_vars()));
11+
}
12+
13+
function doBar(int $param) {
14+
$local = "foo";
15+
if(true) {
16+
$conditional = "bar";
17+
assertType('array{param: int, local: \'foo\', conditional: \'bar\'}', get_defined_vars());
18+
} else {
19+
$other = "baz";
20+
assertType('array{param: int, local: \'foo\', other: \'baz\'}', get_defined_vars());
21+
}
22+
assertType('array{param: int, local: \'foo\', conditional: \'bar\'}', get_defined_vars());
23+
}
24+
25+
function doBaz(int $param) {
26+
$local = "foo";
27+
if(rand(0, 1)) {
28+
$random1 = "bar";
29+
assertType('array{param: int, local: \'foo\', random1: \'bar\'}', get_defined_vars());
30+
} else {
31+
$random2 = "baz";
32+
assertType('array{param: int, local: \'foo\', random2: \'baz\'}', get_defined_vars());
33+
}
34+
assertType('array{param: int, local: \'foo\', random2?: \'baz\', random1?: \'bar\'}', get_defined_vars());
35+
}

0 commit comments

Comments
 (0)