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 <fabien@symfony.com>
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy