Skip to content

Commit 38151b7

Browse files
Fix parse_str issue
1 parent 22f0cab commit 38151b7

File tree

3 files changed

+66
-11
lines changed

3 files changed

+66
-11
lines changed

conf/config.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,6 +1574,11 @@ services:
15741574
tags:
15751575
- phpstan.functionParameterOutTypeExtension
15761576

1577+
-
1578+
class: PHPStan\Type\Php\ParseStrParameterOutTypeExtension
1579+
tags:
1580+
- phpstan.functionParameterOutTypeExtension
1581+
15771582
-
15781583
class: PHPStan\Type\Php\PregReplaceCallbackClosureTypeExtension
15791584
tags:
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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\Reflection\ParameterReflection;
9+
use PHPStan\Type\Accessory\AccessoryLowercaseStringType;
10+
use PHPStan\Type\Accessory\AccessoryUppercaseStringType;
11+
use PHPStan\Type\ArrayType;
12+
use PHPStan\Type\FunctionParameterOutTypeExtension;
13+
use PHPStan\Type\IntegerType;
14+
use PHPStan\Type\IntersectionType;
15+
use PHPStan\Type\MixedType;
16+
use PHPStan\Type\StringType;
17+
use PHPStan\Type\Type;
18+
use PHPStan\Type\UnionType;
19+
20+
use function in_array;
21+
use function strtolower;
22+
23+
final class ParseStrParameterOutTypeExtension implements FunctionParameterOutTypeExtension
24+
{
25+
26+
public function isFunctionSupported(FunctionReflection $functionReflection, ParameterReflection $parameter): bool
27+
{
28+
return in_array(strtolower($functionReflection->getName()), ['parse_str', 'mb_parse_str'], true)
29+
&& $parameter->getName() === 'result';
30+
}
31+
32+
public function getParameterOutTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $funcCall, ParameterReflection $parameter, Scope $scope): ?Type
33+
{
34+
$args = $funcCall->getArgs();
35+
if (count($args) < 1) {
36+
return null;
37+
}
38+
39+
$stringType = $scope->getType($args[0]->value);
40+
$accessory = [];
41+
if ($stringType->isLowercaseString()->yes()) {
42+
$accessory[] = new AccessoryLowercaseStringType();
43+
}
44+
if ($stringType->isUppercaseString()->yes()) {
45+
$accessory[] = new AccessoryUppercaseStringType();
46+
}
47+
if (count($accessory) > 0) {
48+
$valueType = new IntersectionType([new StringType(), ...$accessory]);
49+
} else {
50+
$valueType = new StringType();
51+
}
52+
53+
return new ArrayType(
54+
new UnionType([new StringType(), new IntegerType()]),
55+
new UnionType([new ArrayType(new MixedType(), new MixedType()), $valueType]),
56+
);
57+
}
58+
59+
}

stubs/core.stub

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,22 +69,13 @@ function str_shuffle(string $string): string {}
6969

7070
/**
7171
* @param array<mixed> $result
72-
* @param-out ($string is lowercase-string&uppercase-string
73-
* ? array<int|string, array<mixed>|(lowercase-string&uppercase-string)>
74-
* : ($string is lowercase-string
75-
* ? array<int|string, array<mixed>|lowercase-string>
76-
* : ($string is uppercase-string
77-
* ? array<int|string, array<mixed>|uppercase-string>
78-
* : array<int|string, array<mixed>|string>
79-
* )
80-
* )
81-
* ) $result
72+
* @param-out array<int|string, array<mixed>|string> $result
8273
*/
8374
function parse_str(string $string, array &$result): void {}
8475

8576
/**
8677
* @param array<mixed> $result
87-
* @param-out array<string, array<mixed>|string> $result
78+
* @param-out array<int|string, array<mixed>|string> $result
8879
*/
8980
function mb_parse_str(string $string, array &$result): bool {}
9081

0 commit comments

Comments
 (0)