Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1dedb22

Browse files
minor #47016 Improve some PHPdocs based on existing Symfony stubs in PHPstan and Psalm (mdeboer, wouterj)
This PR was merged into the 6.2 branch. Discussion ---------- Improve some PHPdocs based on existing Symfony stubs in PHPstan and Psalm | Q | A | ------------- | --- | Branch? | 6.2 | Bug fix? | no | New feature? | no | Deprecations? | no (strictly spoken yes, as I guess DebugClassLoader will trigger deprecations for some now?) | Tickets | Replaces #40783 | License | MIT | Doc PR | symfony/symfony-docs#17064 Todo --- * [x] Review the Psalm check of this PR * [x] Test the changes with DebugClassLoader in a real app Description --- This PR adds some more information to the PHPdoc of Symfony classes. By moving the information from the current stubs of static analyzers into Symfony itself: (1) we can improve the experience for all users, (2) reduce false-positives from our own Psalm check and (3) make sure they are in sync with changes done on these classes. <s>To avoid a PR that is too big to review and maintain, the scope of this PR is deliberately kept narrow: * Only PHPdoc from either [Psalm's Symfony stubs](https://github.com/psalm/psalm-plugin-symfony/tree/master/src/Stubs) or [PHPStan's Symfony stubs](https://github.com/phpstan/phpstan-symfony/tree/1.2.x/stubs) is added * The PHPdoc MUST NOT break PHPstorm * The PHPdoc MUST be supported by both PHPstan and Psalm (those are the only two static analyzers that currently ship an official Symfony plugin afaik) * The PHPdoc SHOULD NOT duplicate anything that can already be deduced from either PHP's type declarations or already existing PHPdoc. * The PHPdoc MUST document the contract and NOT be added to fit a 95% use-case or improve auto-completion.</s> EDIT: Replaced the guidelines by symfony/symfony-docs#17064 On top of this, to get this PR approved quicker, I've left out all stubs from the Form (based on the discussions in #40783) and most of [PHPStan's `Envelope` stub](https://github.com/psalm/psalm-plugin-symfony/blob/master/src/Stubs/common/Component/Messenger/Envelope.stubphp) (due to complexity of the PHPdoc). Commits ------- f5a802a [DependencyInjection] Add nice exception when using non-scalar parameter as array key fa7703b [ErrorHandler] Do not patch return types that are not a valid PHP type 38ab6de Improve some PHPdocs based on existing Symfony stubs in PHPstan and Psalm
2 parents e7fbf28 + f5a802a commit 1dedb22

File tree

15 files changed

+108
-44
lines changed

15 files changed

+108
-44
lines changed

.github/expected-missing-return-types.diff

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ index 165797504b..0c0922088a 100644
1818
{
1919
if (!static::$booted) {
2020
diff --git a/src/Symfony/Component/BrowserKit/AbstractBrowser.php b/src/Symfony/Component/BrowserKit/AbstractBrowser.php
21-
index ac25bdf4be..949a036abd 100644
21+
index b27ca37529..5b80175850 100644
2222
--- a/src/Symfony/Component/BrowserKit/AbstractBrowser.php
2323
+++ b/src/Symfony/Component/BrowserKit/AbstractBrowser.php
2424
@@ -408,5 +408,5 @@ abstract class AbstractBrowser
@@ -209,23 +209,30 @@ index 64068fcc23..f29aaf1b94 100644
209209
{
210210
foreach ($command->getHelperSet() as $helper) {
211211
diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php
212-
index 0a3f4b7889..18c2312399 100644
212+
index b41e691537..34de10fa70 100644
213213
--- a/src/Symfony/Component/Console/Command/Command.php
214214
+++ b/src/Symfony/Component/Console/Command/Command.php
215-
@@ -188,5 +188,5 @@ class Command
215+
@@ -189,5 +189,5 @@ class Command
216216
* @return bool
217217
*/
218218
- public function isEnabled()
219219
+ public function isEnabled(): bool
220220
{
221221
return true;
222-
@@ -214,5 +214,5 @@ class Command
222+
@@ -215,5 +215,5 @@ class Command
223223
* @see setCode()
224224
*/
225225
- protected function execute(InputInterface $input, OutputInterface $output)
226226
+ protected function execute(InputInterface $input, OutputInterface $output): int
227227
{
228228
throw new LogicException('You must override the execute() method in the concrete command class.');
229+
@@ -684,5 +684,5 @@ class Command
230+
* @throws InvalidArgumentException if the helper is not defined
231+
*/
232+
- public function getHelper(string $name): mixed
233+
+ public function getHelper(string $name): HelperInterface
234+
{
235+
if (null === $this->helperSet) {
229236
diff --git a/src/Symfony/Component/Console/Formatter/OutputFormatter.php b/src/Symfony/Component/Console/Formatter/OutputFormatter.php
230237
index 3c6b0efccd..121664f15a 100644
231238
--- a/src/Symfony/Component/Console/Formatter/OutputFormatter.php
@@ -283,7 +290,7 @@ index 3af991a76f..742e2508f3 100644
283290

284291
/**
285292
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php
286-
index 70b6c91ff5..cfced387f3 100644
293+
index 2f1631ed30..a4b572771e 100644
287294
--- a/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php
288295
+++ b/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php
289296
@@ -71,5 +71,5 @@ abstract class AbstractRecursivePass implements CompilerPassInterface
@@ -351,31 +358,31 @@ index d553203c43..1163f4b107 100644
351358
{
352359
$class = static::class;
353360
diff --git a/src/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.php b/src/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.php
354-
index f2373ed5ea..1eec21a938 100644
361+
index 4f66f18073..e96d867296 100644
355362
--- a/src/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.php
356363
+++ b/src/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.php
357-
@@ -33,5 +33,5 @@ interface ExtensionInterface
364+
@@ -35,5 +35,5 @@ interface ExtensionInterface
358365
* @return string
359366
*/
360367
- public function getNamespace();
361368
+ public function getNamespace(): string;
362369

363370
/**
364-
@@ -40,5 +40,5 @@ interface ExtensionInterface
371+
@@ -42,5 +42,5 @@ interface ExtensionInterface
365372
* @return string|false
366373
*/
367374
- public function getXsdValidationBasePath();
368375
+ public function getXsdValidationBasePath(): string|false;
369376

370377
/**
371-
@@ -49,4 +49,4 @@ interface ExtensionInterface
378+
@@ -51,4 +51,4 @@ interface ExtensionInterface
372379
* @return string
373380
*/
374381
- public function getAlias();
375382
+ public function getAlias(): string;
376383
}
377384
diff --git a/src/Symfony/Component/DependencyInjection/LazyProxy/Instantiator/InstantiatorInterface.php b/src/Symfony/Component/DependencyInjection/LazyProxy/Instantiator/InstantiatorInterface.php
378-
index a9d78115dd..8b3b420a9c 100644
385+
index 92c4b44845..ae557d8bca 100644
379386
--- a/src/Symfony/Component/DependencyInjection/LazyProxy/Instantiator/InstantiatorInterface.php
380387
+++ b/src/Symfony/Component/DependencyInjection/LazyProxy/Instantiator/InstantiatorInterface.php
381388
@@ -31,4 +31,4 @@ interface InstantiatorInterface
@@ -568,10 +575,10 @@ index 1cb865fd66..f6f4efe7a7 100644
568575
+ public function getName(): string;
569576
}
570577
diff --git a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
571-
index 45ff4a006c..611259b3b6 100644
578+
index d97064da8b..d76c73df90 100644
572579
--- a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
573580
+++ b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
574-
@@ -448,5 +448,5 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
581+
@@ -463,5 +463,5 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
575582
* @return Response
576583
*/
577584
- protected function forward(Request $request, bool $catch = false, Response $entry = null)
@@ -776,7 +783,7 @@ index 6da0bcb4c8..16e9765b1d 100644
776783
+ public function getTypes(string $class, string $property, array $context = []): ?array;
777784
}
778785
diff --git a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php
779-
index 204e9b3341..8e624e1154 100644
786+
index 5f3a852d32..65a18bd924 100644
780787
--- a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php
781788
+++ b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php
782789
@@ -253,5 +253,5 @@ abstract class AnnotationClassLoader implements LoaderInterface
@@ -808,7 +815,7 @@ index 6912f8a15b..caf18c886a 100644
808815
+ public function getRouteCollection(): RouteCollection;
809816
}
810817
diff --git a/src/Symfony/Component/Security/Core/Authentication/RememberMe/TokenProviderInterface.php b/src/Symfony/Component/Security/Core/Authentication/RememberMe/TokenProviderInterface.php
811-
index eda4730004..00cfc5b9c7 100644
818+
index 9b32fdce31..fbbd65d8b7 100644
812819
--- a/src/Symfony/Component/Security/Core/Authentication/RememberMe/TokenProviderInterface.php
813820
+++ b/src/Symfony/Component/Security/Core/Authentication/RememberMe/TokenProviderInterface.php
814821
@@ -28,5 +28,5 @@ interface TokenProviderInterface
@@ -819,11 +826,11 @@ index eda4730004..00cfc5b9c7 100644
819826

820827
/**
821828
diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/VoterInterface.php b/src/Symfony/Component/Security/Core/Authorization/Voter/VoterInterface.php
822-
index 7e401c3ff3..6b446ff376 100644
829+
index ba52c8ea65..e879a84982 100644
823830
--- a/src/Symfony/Component/Security/Core/Authorization/Voter/VoterInterface.php
824831
+++ b/src/Symfony/Component/Security/Core/Authorization/Voter/VoterInterface.php
825-
@@ -36,4 +36,4 @@ interface VoterInterface
826-
* @return int either ACCESS_GRANTED, ACCESS_ABSTAIN, or ACCESS_DENIED
832+
@@ -37,4 +37,4 @@ interface VoterInterface
833+
* @psalm-return self::ACCESS_* must be transformed into @return on Symfony 7
827834
*/
828835
- public function vote(TokenInterface $token, mixed $subject, array $attributes);
829836
+ public function vote(TokenInterface $token, mixed $subject, array $attributes): int;
@@ -889,7 +896,7 @@ index 480ea8ad6b..fa43d6a6e9 100644
889896
+ public function getListeners(Request $request): array;
890897
}
891898
diff --git a/src/Symfony/Component/Serializer/Encoder/DecoderInterface.php b/src/Symfony/Component/Serializer/Encoder/DecoderInterface.php
892-
index f38069e471..0966eb3e89 100644
899+
index 5014b9bd51..757c76f546 100644
893900
--- a/src/Symfony/Component/Serializer/Encoder/DecoderInterface.php
894901
+++ b/src/Symfony/Component/Serializer/Encoder/DecoderInterface.php
895902
@@ -35,5 +35,5 @@ interface DecoderInterface
@@ -906,7 +913,7 @@ index f38069e471..0966eb3e89 100644
906913
+ public function supportsDecoding(string $format /* , array $context = [] */): bool;
907914
}
908915
diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php
909-
index 44ba45f581..3398115497 100644
916+
index 391cdcb39c..f637687e74 100644
910917
--- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php
911918
+++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php
912919
@@ -213,5 +213,5 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn
@@ -931,7 +938,7 @@ index 44ba45f581..3398115497 100644
931938
{
932939
if (null !== $object = $this->extractObjectToPopulate($class, $context, self::OBJECT_TO_POPULATE)) {
933940
diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
934-
index 511dd1c724..c319e1839b 100644
941+
index 714fb10e30..ea3f4428bf 100644
935942
--- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
936943
+++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
937944
@@ -139,5 +139,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
@@ -948,43 +955,43 @@ index 511dd1c724..c319e1839b 100644
948955
+ public function normalize(mixed $object, string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null
949956
{
950957
if (!isset($context['cache_key'])) {
951-
@@ -265,5 +265,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
958+
@@ -230,5 +230,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
952959
* {@inheritdoc}
953960
*/
954961
- protected function instantiateObject(array &$data, string $class, array &$context, \ReflectionClass $reflectionClass, array|bool $allowedAttributes, string $format = null)
955962
+ protected function instantiateObject(array &$data, string $class, array &$context, \ReflectionClass $reflectionClass, array|bool $allowedAttributes, string $format = null): object
956963
{
957964
if ($this->classDiscriminatorResolver && $mapping = $this->classDiscriminatorResolver->getMappingForClass($class)) {
958-
@@ -327,5 +327,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
965+
@@ -292,5 +292,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
959966
* @return string[]
960967
*/
961968
- abstract protected function extractAttributes(object $object, string $format = null, array $context = []);
962969
+ abstract protected function extractAttributes(object $object, string $format = null, array $context = []): array;
963970

964971
/**
965-
@@ -334,5 +334,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
972+
@@ -299,5 +299,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
966973
* @return mixed
967974
*/
968975
- abstract protected function getAttributeValue(object $object, string $attribute, string $format = null, array $context = []);
969976
+ abstract protected function getAttributeValue(object $object, string $attribute, string $format = null, array $context = []): mixed;
970977

971978
/**
972-
@@ -341,5 +341,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
979+
@@ -306,5 +306,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
973980
* @param array $context
974981
*/
975982
- public function supportsDenormalization(mixed $data, string $type, string $format = null /* , array $context = [] */)
976983
+ public function supportsDenormalization(mixed $data, string $type, string $format = null /* , array $context = [] */): bool
977984
{
978985
return class_exists($type) || (interface_exists($type, false) && $this->classDiscriminatorResolver && null !== $this->classDiscriminatorResolver->getMappingForClass($type));
979-
@@ -349,5 +349,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
986+
@@ -314,5 +314,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
980987
* {@inheritdoc}
981988
*/
982989
- public function denormalize(mixed $data, string $type, string $format = null, array $context = [])
983990
+ public function denormalize(mixed $data, string $type, string $format = null, array $context = []): mixed
984991
{
985992
if (!isset($context['cache_key'])) {
986993
diff --git a/src/Symfony/Component/Serializer/Normalizer/DenormalizerInterface.php b/src/Symfony/Component/Serializer/Normalizer/DenormalizerInterface.php
987-
index 1c708738a1..3b6c9d5056 100644
994+
index ae3adbfe33..3a38429cf1 100644
988995
--- a/src/Symfony/Component/Serializer/Normalizer/DenormalizerInterface.php
989996
+++ b/src/Symfony/Component/Serializer/Normalizer/DenormalizerInterface.php
990997
@@ -45,5 +45,5 @@ interface DenormalizerInterface
@@ -1001,7 +1008,7 @@ index 1c708738a1..3b6c9d5056 100644
10011008
+ public function supportsDenormalization(mixed $data, string $type, string $format = null /* , array $context = [] */): bool;
10021009
}
10031010
diff --git a/src/Symfony/Component/Serializer/Normalizer/NormalizerInterface.php b/src/Symfony/Component/Serializer/Normalizer/NormalizerInterface.php
1004-
index 741f19e50b..acf3be931b 100644
1011+
index 691e9c70f0..fc87f672e1 100644
10051012
--- a/src/Symfony/Component/Serializer/Normalizer/NormalizerInterface.php
10061013
+++ b/src/Symfony/Component/Serializer/Normalizer/NormalizerInterface.php
10071014
@@ -37,5 +37,5 @@ interface NormalizerInterface
@@ -1077,7 +1084,7 @@ index ee1d68c78f..9baaabb04c 100644
10771084
{
10781085
return self::PROPERTY_CONSTRAINT;
10791086
diff --git a/src/Symfony/Component/VarExporter/Internal/Exporter.php b/src/Symfony/Component/VarExporter/Internal/Exporter.php
1080-
index f7ef22df5c..9439e9526f 100644
1087+
index b22d6ae609..31d1a25f9d 100644
10811088
--- a/src/Symfony/Component/VarExporter/Internal/Exporter.php
10821089
+++ b/src/Symfony/Component/VarExporter/Internal/Exporter.php
10831090
@@ -36,5 +36,5 @@ class Exporter

src/Symfony/Component/Console/Command/Command.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\Console\Exception\ExceptionInterface;
2020
use Symfony\Component\Console\Exception\InvalidArgumentException;
2121
use Symfony\Component\Console\Exception\LogicException;
22+
use Symfony\Component\Console\Helper\HelperInterface;
2223
use Symfony\Component\Console\Helper\HelperSet;
2324
use Symfony\Component\Console\Input\InputArgument;
2425
use Symfony\Component\Console\Input\InputDefinition;
@@ -677,6 +678,8 @@ public function getUsages(): array
677678
/**
678679
* Gets a helper instance by name.
679680
*
681+
* @return HelperInterface
682+
*
680683
* @throws LogicException if no HelperSet is defined
681684
* @throws InvalidArgumentException if the helper is not defined
682685
*/

src/Symfony/Component/Console/Command/LazyCommand.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\Console\Completion\CompletionInput;
1616
use Symfony\Component\Console\Completion\CompletionSuggestions;
1717
use Symfony\Component\Console\Completion\Suggestion;
18+
use Symfony\Component\Console\Helper\HelperInterface;
1819
use Symfony\Component\Console\Helper\HelperSet;
1920
use Symfony\Component\Console\Input\InputDefinition;
2021
use Symfony\Component\Console\Input\InputInterface;
@@ -176,7 +177,7 @@ public function getUsages(): array
176177
return $this->getCommand()->getUsages();
177178
}
178179

179-
public function getHelper(string $name): mixed
180+
public function getHelper(string $name): HelperInterface
180181
{
181182
return $this->getCommand()->getHelper($name);
182183
}

src/Symfony/Component/Console/Helper/HelperSet.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@
1818
*
1919
* @author Fabien Potencier <[email protected]>
2020
*
21-
* @implements \IteratorAggregate<string, Helper>
21+
* @implements \IteratorAggregate<string, HelperInterface>
2222
*/
2323
class HelperSet implements \IteratorAggregate
2424
{
25-
/** @var array<string, Helper> */
25+
/** @var array<string, HelperInterface> */
2626
private array $helpers = [];
2727

2828
/**
29-
* @param Helper[] $helpers An array of helper
29+
* @param HelperInterface[] $helpers
3030
*/
3131
public function __construct(array $helpers = [])
3232
{

src/Symfony/Component/Console/Output/OutputInterface.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,17 @@ interface OutputInterface
3333
/**
3434
* Writes a message to the output.
3535
*
36-
* @param $newline Whether to add a newline
37-
* @param $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
36+
* @param bool $newline Whether to add a newline
37+
* @param self::VERBOSITY_*|self::OUTPUT_* $options A bitmask of options (one of the OUTPUT or VERBOSITY constants),
38+
* 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
3839
*/
3940
public function write(string|iterable $messages, bool $newline = false, int $options = 0);
4041

4142
/**
4243
* Writes a message to the output and adds a newline at the end.
4344
*
44-
* @param $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
45+
* @param self::VERBOSITY_*|self::OUTPUT_* $options A bitmask of options (one of the OUTPUT or VERBOSITY constants),
46+
* 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
4547
*/
4648
public function writeln(string|iterable $messages, int $options = 0);
4749

src/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ interface ExtensionInterface
2323
/**
2424
* Loads a specific configuration.
2525
*
26+
* @param array<array<mixed>> $configs
27+
*
2628
* @throws \InvalidArgumentException When provided tag is not defined in this extension
2729
*/
2830
public function load(array $configs, ContainerBuilder $container);

src/Symfony/Component/DependencyInjection/ParameterBag/ContainerBagInterface.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ public function all(): array;
2929
/**
3030
* Replaces parameter placeholders (%name%) by their values.
3131
*
32+
* @template TValue of array<array|scalar>|scalar
33+
*
34+
* @param TValue $value
35+
*
36+
* @psalm-return (TValue is scalar ? array|scalar : array<array|scalar>)
37+
*
3238
* @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
3339
*/
3440
public function resolveValue(mixed $value);

src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,12 @@ public function resolve()
148148
/**
149149
* Replaces parameter placeholders (%name%) by their values.
150150
*
151-
* @param array $resolving An array of keys that are being resolved (used internally to detect circular references)
151+
* @template TValue of array<array|scalar>|scalar
152+
*
153+
* @param TValue $value
154+
* @param array $resolving An array of keys that are being resolved (used internally to detect circular references)
155+
*
156+
* @return (TValue is scalar ? array|scalar : array<array|scalar>)
152157
*
153158
* @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
154159
* @throws ParameterCircularReferenceException if a circular reference if detected
@@ -158,8 +163,13 @@ public function resolveValue(mixed $value, array $resolving = []): mixed
158163
{
159164
if (\is_array($value)) {
160165
$args = [];
161-
foreach ($value as $k => $v) {
162-
$args[\is_string($k) ? $this->resolveValue($k, $resolving) : $k] = $this->resolveValue($v, $resolving);
166+
foreach ($value as $key => $v) {
167+
$resolvedKey = \is_string($key) ? $this->resolveValue($key, $resolving) : $key;
168+
if (!\is_scalar($resolvedKey) && !$resolvedKey instanceof \Stringable) {
169+
throw new RuntimeException(sprintf('Array keys must be a scalar-value, but found key "%s" to resolve to type "%s".', $key, get_debug_type($resolvedKey)));
170+
}
171+
172+
$args[$resolvedKey] = $this->resolveValue($v, $resolving);
163173
}
164174

165175
return $args;

src/Symfony/Component/ErrorHandler/DebugClassLoader.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,11 @@ private function setReturnType(string $types, string $class, string $method, str
855855
return;
856856
}
857857

858+
if (!preg_match('/^(?:\\\\?[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)+$/', $n)) {
859+
// exclude any invalid PHP class name (e.g. `Cookie::SAMESITE_*`)
860+
continue;
861+
}
862+
858863
if (!isset($phpTypes[''])) {
859864
$phpTypes[] = $n;
860865
}

0 commit comments

Comments
 (0)