From eef0c91e2fad9030009240bdfddb2df8e40018b9 Mon Sep 17 00:00:00 2001 From: ChrisAbner Date: Wed, 28 Oct 2026 18:43:45 -0500 Subject: [PATCH] Load the ParameterBag stub until symfony/http-foundation 8.2 ParameterBag::keys() and all() return the parameters' own keys, so a numeric parameter name comes back as an int on every released version, while Symfony 7.4+ documents keys() as list and all() as array. The stub was only loaded below 7.4, so a correct is_string() guard over those keys was reported as always true. Symfony 8.2 casts the keys to strings and documents all() as array (symfony/symfony#66127), so the stub is now loaded below 8.2, and it covers all() as well. The InputBag and Request stubs keep their 7.4 gate. --- src/Stubs/Symfony/StubFilesExtensionLoader.php | 14 +++++++++----- .../Component/HttpFoundation/ParameterBag.stub | 7 +++++++ tests/Type/Symfony/ExtensionTest.php | 1 + tests/Type/Symfony/data/parameter_bag.php | 13 +++++++++++++ 4 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 tests/Type/Symfony/data/parameter_bag.php diff --git a/src/Stubs/Symfony/StubFilesExtensionLoader.php b/src/Stubs/Symfony/StubFilesExtensionLoader.php index 9b4ea3be..4e345147 100644 --- a/src/Stubs/Symfony/StubFilesExtensionLoader.php +++ b/src/Stubs/Symfony/StubFilesExtensionLoader.php @@ -68,13 +68,17 @@ public function getFiles(): array $files[] = $stubsDir . '/Symfony/Component/HttpFoundation/Cookie.stub'; } - if ($this->isInstalledVersionBelow('symfony/http-foundation', '7.4.0.0')) { + // keys() returns int keys for numeric parameter names until symfony/http-foundation 8.2 casts them to string + if ($this->isInstalledVersionBelow('symfony/http-foundation', '8.2.0.0')) { $files[] = $stubsDir . '/Symfony/Component/HttpFoundation/ParameterBag.stub'; + } - if (!$this->isInstalledVersionBelow('symfony/http-foundation', '5.1.0.0')) { - $files[] = $stubsDir . '/Symfony/Component/HttpFoundation/InputBag.stub'; - $files[] = $stubsDir . '/Symfony/Component/HttpFoundation/Request.stub'; - } + if ( + $this->isInstalledVersionBelow('symfony/http-foundation', '7.4.0.0') + && !$this->isInstalledVersionBelow('symfony/http-foundation', '5.1.0.0') + ) { + $files[] = $stubsDir . '/Symfony/Component/HttpFoundation/InputBag.stub'; + $files[] = $stubsDir . '/Symfony/Component/HttpFoundation/Request.stub'; } if ($this->isInstalledVersionBelow('symfony/messenger', '6.1.0.0')) { diff --git a/stubs/Symfony/Component/HttpFoundation/ParameterBag.stub b/stubs/Symfony/Component/HttpFoundation/ParameterBag.stub index e412e9e0..345fce90 100644 --- a/stubs/Symfony/Component/HttpFoundation/ParameterBag.stub +++ b/stubs/Symfony/Component/HttpFoundation/ParameterBag.stub @@ -7,6 +7,13 @@ namespace Symfony\Component\HttpFoundation; */ class ParameterBag implements \IteratorAggregate { + /** + * @return array + */ + public function all(?string $key = null): array + { + } + /** * @return list */ diff --git a/tests/Type/Symfony/ExtensionTest.php b/tests/Type/Symfony/ExtensionTest.php index 7e965cf5..84b28bb4 100644 --- a/tests/Type/Symfony/ExtensionTest.php +++ b/tests/Type/Symfony/ExtensionTest.php @@ -25,6 +25,7 @@ public function dataFileAsserts(): iterable yield from $this->gatherAssertTypes(__DIR__ . '/data/traceable_message_bus.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/header_bag_get.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/data/parameter_bag.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/response_header_bag_get_cookies.php'); if (class_exists('Symfony\Component\HttpFoundation\InputBag')) { diff --git a/tests/Type/Symfony/data/parameter_bag.php b/tests/Type/Symfony/data/parameter_bag.php new file mode 100644 index 00000000..4f3b7c91 --- /dev/null +++ b/tests/Type/Symfony/data/parameter_bag.php @@ -0,0 +1,13 @@ + 'bar']); + +assertType('list<(int|string)>', $bag->keys()); +assertType('array', $bag->all()); +assertType('array', $bag->all('foo')); + +foreach ($bag as $key => $value) { + assertType('(int|string)', $key); +}