Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2063d60

Browse files
DIC parameters: do not generalize string-indexed arrays
1 parent 5d2d5ad commit 2063d60

File tree

6 files changed

+78
-6
lines changed

6 files changed

+78
-6
lines changed

‎src/Type/Symfony/ParameterDynamicReturnTypeExtension.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
use PHPStan\Type\BooleanType;
1515
use PHPStan\Type\Constant\ConstantArrayType;
1616
use PHPStan\Type\Constant\ConstantBooleanType;
17+
use PHPStan\Type\Constant\ConstantIntegerType;
18+
use PHPStan\Type\Constant\ConstantStringType;
1719
use PHPStan\Type\ConstantType;
1820
use PHPStan\Type\DynamicMethodReturnTypeExtension;
1921
use PHPStan\Type\FloatType;
@@ -35,6 +37,7 @@
3537
use function count;
3638
use function in_array;
3739
use function is_array;
40+
use function is_int;
3841
use function is_string;
3942
use function preg_match;
4043
use function strlen;
@@ -139,6 +142,27 @@ private function getGetTypeFromMethodCall(
139142
private function generalizeTypeFromValue(Scope $scope, $value): Type
140143
{
141144
if (is_array($value) && $value !== []) {
145+
$hasOnlyStringKey = true;
146+
foreach (array_keys($value) as $key) {
147+
if (is_int($key)) {
148+
$hasOnlyStringKey = false;
149+
break;
150+
}
151+
}
152+
153+
if ($hasOnlyStringKey) {
154+
$keyTypes = [];
155+
$valueTypes = [];
156+
foreach ($value as $key => $element) {
157+
/** @var ConstantIntegerType|ConstantStringType $keyType */
158+
$keyType = $scope->getTypeFromValue($key);
159+
$keyTypes[] = $keyType;
160+
$valueTypes[] = $this->generalizeTypeFromValue($scope, $element);
161+
}
162+
163+
return new ConstantArrayType($keyTypes, $valueTypes);
164+
}
165+
142166
return $this->generalizeType(
143167
new ArrayType(
144168
TypeCombinator::union(...array_map(function ($item) use ($scope): Type {

‎tests/Type/Symfony/container.xml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,36 @@
3737
<parameter key="value">another value</parameter>
3838
</parameter>
3939
</parameter>
40+
<parameter key="app.array_of_list" type="collection">
41+
<parameter key="foo" type="collection">
42+
<parameter key="name">the name</parameter>
43+
<parameter key="value">the value</parameter>
44+
</parameter>
45+
<parameter type="collection">
46+
<parameter key="name">another name</parameter>
47+
<parameter key="value">another value</parameter>
48+
</parameter>
49+
</parameter>
50+
<parameter key="app.list_of_things" type="collection">
51+
<parameter key="url">%env(string:APP_STRING)%</parameter>
52+
<parameter key="endpoint">%env(string:APP_STRING)%</parameter>
53+
<parameter key="version">%env(string:APP_STRING)%</parameter>
54+
<parameter key="payment" type="collection">
55+
<parameter key="default" type="collection">
56+
<parameter key="username">%env(string:APP_STRING)%</parameter>
57+
<parameter key="password">%env(string:APP_STRING)%</parameter>
58+
<parameter key="signature">%env(string:APP_STRING)%</parameter>
59+
</parameter>
60+
</parameter>
61+
<parameter key="api" type="collection">
62+
<parameter key="mode">%env(string:APP_STRING)%</parameter>
63+
<parameter key="default" type="collection">
64+
<parameter key="username">%env(string:APP_STRING)%</parameter>
65+
<parameter key="password">%env(string:APP_STRING)%</parameter>
66+
<parameter key="signature">%env(string:APP_STRING)%</parameter>
67+
</parameter>
68+
</parameter>
69+
</parameter>
4070
<parameter key="app.map" type="collection">
4171
<parameter key="a">value of a</parameter>
4272
<parameter key="b">value of b</parameter>

‎tests/Type/Symfony/data/ExampleAbstractController.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,15 @@ public function parameters(ContainerInterface $container, ParameterBagInterface
6868
assertType("array<int, array<string, string>>", $container->getParameter('app.list_of_list'));
6969
assertType("array<int, array<string, string>>", $parameterBag->get('app.list_of_list'));
7070
assertType("array<int, array<string, string>>", $this->getParameter('app.list_of_list'));
71-
assertType("array<string, string>", $container->getParameter('app.map'));
72-
assertType("array<string, string>", $parameterBag->get('app.map'));
73-
assertType("array<string, string>", $this->getParameter('app.map'));
71+
assertType("array<int|string, array<string, string>>", $container->getParameter('app.array_of_list'));
72+
assertType("array<int|string, array<string, string>>", $parameterBag->get('app.array_of_list'));
73+
assertType("array<int|string, array<string, string>>", $this->getParameter('app.array_of_list'));
74+
assertType("array{url: string, endpoint: string, version: string, payment: array{default: array{username: string, password: string, signature: string}}, api: array{mode: string, default: array{username: string, password: string, signature: string}}}", $container->getParameter('app.list_of_things'));
75+
assertType("array{url: string, endpoint: string, version: string, payment: array{default: array{username: string, password: string, signature: string}}, api: array{mode: string, default: array{username: string, password: string, signature: string}}}", $parameterBag->get('app.list_of_things'));
76+
assertType("array{url: string, endpoint: string, version: string, payment: array{default: array{username: string, password: string, signature: string}}, api: array{mode: string, default: array{username: string, password: string, signature: string}}}", $this->getParameter('app.list_of_things'));
77+
assertType("array{a: string, b: string, c: string}", $container->getParameter('app.map'));
78+
assertType("array{a: string, b: string, c: string}", $parameterBag->get('app.map'));
79+
assertType("array{a: string, b: string, c: string}", $this->getParameter('app.map'));
7480
assertType("string", $container->getParameter('app.binary'));
7581
assertType("string", $parameterBag->get('app.binary'));
7682
assertType("string", $this->getParameter('app.binary'));

‎tests/Type/Symfony/data/ExampleAbstractControllerWithoutContainer.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ public function parameters(ContainerInterface $container, ParameterBagInterface
6565
assertType('array|bool|float|int|string|null', $container->getParameter('app.list_of_list'));
6666
assertType('array|bool|float|int|string|null', $parameterBag->get('app.list_of_list'));
6767
assertType('array|bool|float|int|string|null', $this->getParameter('app.list_of_list'));
68+
assertType('array|bool|float|int|string|null', $container->getParameter('app.array_of_list'));
69+
assertType('array|bool|float|int|string|null', $parameterBag->get('app.array_of_list'));
70+
assertType('array|bool|float|int|string|null', $this->getParameter('app.array_of_list'));
6871
assertType('array|bool|float|int|string|null', $container->getParameter('app.map'));
6972
assertType('array|bool|float|int|string|null', $parameterBag->get('app.map'));
7073
assertType('array|bool|float|int|string|null', $this->getParameter('app.map'));

‎tests/Type/Symfony/data/ExampleController.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,15 @@ public function parameters(ContainerInterface $container, ParameterBagInterface
6868
assertType("array<int, array<string, string>>", $container->getParameter('app.list_of_list'));
6969
assertType("array<int, array<string, string>>", $parameterBag->get('app.list_of_list'));
7070
assertType("array<int, array<string, string>>", $this->getParameter('app.list_of_list'));
71-
assertType("array<string, string>", $container->getParameter('app.map'));
72-
assertType("array<string, string>", $parameterBag->get('app.map'));
73-
assertType("array<string, string>", $this->getParameter('app.map'));
71+
assertType("array<int|string, array<string, string>>", $container->getParameter('app.array_of_list'));
72+
assertType("array<int|string, array<string, string>>", $parameterBag->get('app.array_of_list'));
73+
assertType("array<int|string, array<string, string>>", $this->getParameter('app.array_of_list'));
74+
assertType("array{url: string, endpoint: string, version: string, payment: array{default: array{username: string, password: string, signature: string}}, api: array{mode: string, default: array{username: string, password: string, signature: string}}}", $container->getParameter('app.list_of_things'));
75+
assertType("array{url: string, endpoint: string, version: string, payment: array{default: array{username: string, password: string, signature: string}}, api: array{mode: string, default: array{username: string, password: string, signature: string}}}", $parameterBag->get('app.list_of_things'));
76+
assertType("array{url: string, endpoint: string, version: string, payment: array{default: array{username: string, password: string, signature: string}}, api: array{mode: string, default: array{username: string, password: string, signature: string}}}", $this->getParameter('app.list_of_things'));
77+
assertType("array{a: string, b: string, c: string}", $container->getParameter('app.map'));
78+
assertType("array{a: string, b: string, c: string}", $parameterBag->get('app.map'));
79+
assertType("array{a: string, b: string, c: string}", $this->getParameter('app.map'));
7480
assertType("string", $container->getParameter('app.binary'));
7581
assertType("string", $parameterBag->get('app.binary'));
7682
assertType("string", $this->getParameter('app.binary'));

‎tests/Type/Symfony/data/ExampleControllerWithoutContainer.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ public function parameters(ContainerInterface $container, ParameterBagInterface
6565
assertType('array|bool|float|int|string|null', $container->getParameter('app.list_of_list'));
6666
assertType('array|bool|float|int|string|null', $parameterBag->get('app.list_of_list'));
6767
assertType('array|bool|float|int|string|null', $this->getParameter('app.list_of_list'));
68+
assertType('array|bool|float|int|string|null', $container->getParameter('app.array_of_list'));
69+
assertType('array|bool|float|int|string|null', $parameterBag->get('app.array_of_list'));
70+
assertType('array|bool|float|int|string|null', $this->getParameter('app.array_of_list'));
6871
assertType('array|bool|float|int|string|null', $container->getParameter('app.map'));
6972
assertType('array|bool|float|int|string|null', $parameterBag->get('app.map'));
7073
assertType('array|bool|float|int|string|null', $this->getParameter('app.map'));

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /