Skip to content

Commit 8d67d7a

Browse files
MartinMystikJonasruudk
authored andcommitted
get_defined_vars() return type contains known variables
Co-Authored-By: Ruud Kamphuis <ruudk@users.noreply.github.com>
1 parent 62c6a0a commit 8d67d7a

File tree

3 files changed

+97
-0
lines changed

3 files changed

+97
-0
lines changed

conf/config.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,6 +1525,11 @@ services:
15251525
tags:
15261526
- phpstan.broker.dynamicFunctionReturnTypeExtension
15271527

1528+
-
1529+
class: PHPStan\Type\Php\GetDefinedVarsFunctionReturnTypeExtension
1530+
tags:
1531+
- phpstan.broker.dynamicFunctionReturnTypeExtension
1532+
15281533
-
15291534
class: PHPStan\Type\Php\GetParentClassDynamicFunctionReturnTypeExtension
15301535
tags:
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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\ConstantArrayTypeBuilder;
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+
16+
final class GetDefinedVarsFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension
17+
{
18+
19+
public function isFunctionSupported(FunctionReflection $functionReflection): bool
20+
{
21+
return $functionReflection->getName() === 'get_defined_vars';
22+
}
23+
24+
public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): Type
25+
{
26+
if ($scope->canAnyVariableExist()) {
27+
return new ArrayType(
28+
new StringType(),
29+
new MixedType(),
30+
);
31+
}
32+
33+
$typeBuilder = ConstantArrayTypeBuilder::createEmpty();
34+
35+
foreach ($scope->getDefinedVariables() as $variable) {
36+
$typeBuilder->setOffsetValueType(new ConstantStringType($variable), $scope->getVariableType($variable), false);
37+
}
38+
39+
foreach ($scope->getMaybeDefinedVariables() as $variable) {
40+
$typeBuilder->setOffsetValueType(new ConstantStringType($variable), $scope->getVariableType($variable), true);
41+
}
42+
43+
return $typeBuilder->getArray();
44+
}
45+
46+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
namespace GetDefinedVars;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
$global = "foo";
8+
9+
assertType('array<string, mixed>', get_defined_vars()); // any variable can exist
10+
11+
function doFoo(int $param) {
12+
$local = "foo";
13+
assertType('array{param: int, local: \'foo\'}', get_defined_vars());
14+
assertType('array{\'param\', \'local\'}', array_keys(get_defined_vars()));
15+
}
16+
17+
function doBar(int $param) {
18+
global $global;
19+
$local = "foo";
20+
assertType('array{param: int, global: mixed, local: \'foo\'}', get_defined_vars());
21+
assertType('array{\'param\', \'global\', \'local\'}', array_keys(get_defined_vars()));
22+
}
23+
24+
function doConditional(int $param) {
25+
$local = "foo";
26+
if(true) {
27+
$conditional = "bar";
28+
assertType('array{param: int, local: \'foo\', conditional: \'bar\'}', get_defined_vars());
29+
} else {
30+
$other = "baz";
31+
assertType('array{param: int, local: \'foo\', other: \'baz\'}', get_defined_vars());
32+
}
33+
assertType('array{param: int, local: \'foo\', conditional: \'bar\'}', get_defined_vars());
34+
}
35+
36+
function doRandom(int $param) {
37+
$local = "foo";
38+
if(rand(0, 1)) {
39+
$random1 = "bar";
40+
assertType('array{param: int, local: \'foo\', random1: \'bar\'}', get_defined_vars());
41+
} else {
42+
$random2 = "baz";
43+
assertType('array{param: int, local: \'foo\', random2: \'baz\'}', get_defined_vars());
44+
}
45+
assertType('array{param: int, local: \'foo\', random2?: \'baz\', random1?: \'bar\'}', get_defined_vars());
46+
}

0 commit comments

Comments
 (0)