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

Skip to content

Commit 5a86bf2

Browse files
Fix support for PHP8 union types
1 parent bf2fb93 commit 5a86bf2

File tree

18 files changed

+127
-67
lines changed

18 files changed

+127
-67
lines changed

src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public function registerContainerConfiguration(LoaderInterface $loader)
112112
throw new \LogicException(sprintf('"%s" uses "%s", but does not implement the required method "protected function configureContainer(ContainerConfigurator $c): void".', get_debug_type($this), MicroKernelTrait::class), 0, $e);
113113
}
114114

115-
$configuratorClass = $configureContainer->getNumberOfParameters() > 0 && ($type = $configureContainer->getParameters()[0]->getType()) && !$type->isBuiltin() ? $type->getName() : null;
115+
$configuratorClass = $configureContainer->getNumberOfParameters() > 0 && ($type = $configureContainer->getParameters()[0]->getType()) instanceof \ReflectionNamedType && !$type->isBuiltin() ? $type->getName() : null;
116116

117117
if ($configuratorClass && !is_a(ContainerConfigurator::class, $configuratorClass, true)) {
118118
$this->configureContainer($container, $loader);

src/Symfony/Component/Config/Resource/ReflectionClassResource.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ private function generateSignature(\ReflectionClass $class): iterable
169169
if (!$parametersWithUndefinedConstants) {
170170
yield preg_replace('/^ @@.*/m', '', $m);
171171
} else {
172+
$t = $m->getReturnType();
172173
$stack = [
173174
$m->getDocComment(),
174175
$m->getName(),
@@ -179,15 +180,16 @@ private function generateSignature(\ReflectionClass $class): iterable
179180
$m->isPrivate(),
180181
$m->isProtected(),
181182
$m->returnsReference(),
182-
$m->hasReturnType() ? $m->getReturnType()->getName() : '',
183+
$t instanceof \ReflectionNamedType ? ((string) $t->allowsNull()).$t->getName() : (string) $t,
183184
];
184185

185186
foreach ($m->getParameters() as $p) {
186187
if (!isset($parametersWithUndefinedConstants[$p->name])) {
187188
$stack[] = (string) $p;
188189
} else {
190+
$t = $p->getType();
189191
$stack[] = $p->isOptional();
190-
$stack[] = $p->hasType() ? $p->getType()->getName() : '';
192+
$stack[] = $t instanceof \ReflectionNamedType ? ((string) $t->allowsNull()).$t->getName() : (string) $t;
191193
$stack[] = $p->isPassedByReference();
192194
$stack[] = $p->isVariadic();
193195
$stack[] = $p->getName();

src/Symfony/Component/DependencyInjection/Compiler/AutowireRequiredPropertiesPass.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ protected function processValue($value, bool $isRoot = false)
4242

4343
$properties = $value->getProperties();
4444
foreach ($reflectionClass->getProperties() as $reflectionProperty) {
45-
if (!$reflectionProperty->hasType()) {
45+
if (!($type = $reflectionProperty->getType()) instanceof \ReflectionNamedType) {
4646
continue;
4747
}
4848
if (false === $doc = $reflectionProperty->getDocComment()) {
@@ -55,7 +55,7 @@ protected function processValue($value, bool $isRoot = false)
5555
continue;
5656
}
5757

58-
$type = $reflectionProperty->getType()->getName();
58+
$type = $type->getName();
5959
$value->setProperty($name, new TypedReference($type, $type, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $name));
6060
}
6161

src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,25 @@ private function checkTypeDeclarations(Definition $checkedDefinition, \Reflectio
153153
/**
154154
* @throws InvalidParameterTypeException When a parameter is not compatible with the declared type
155155
*/
156-
private function checkType(Definition $checkedDefinition, $value, \ReflectionParameter $parameter, ?string $envPlaceholderUniquePrefix): void
156+
private function checkType(Definition $checkedDefinition, $value, \ReflectionParameter $parameter, ?string $envPlaceholderUniquePrefix, string $type = null): void
157157
{
158-
$type = $parameter->getType()->getName();
158+
if (null === $type) {
159+
$type = $parameter->getType();
160+
161+
if ($type instanceof \ReflectionUnionType) {
162+
foreach ($type->getTypes() as $type) {
163+
try {
164+
$this->checkType($checkedDefinition, $value, $parameter, $envPlaceholderUniquePrefix, $type);
165+
return;
166+
} catch (InvalidParameterTypeException $e) {
167+
}
168+
}
169+
170+
throw new InvalidParameterTypeException($this->currentId, $e->getCode(), $parameter);
171+
}
172+
173+
$type = $type->getName();
174+
}
159175

160176
if ($value instanceof Reference) {
161177
if (!$this->container->has($value = (string) $value)) {
@@ -266,7 +282,7 @@ private function checkType(Definition $checkedDefinition, $value, \ReflectionPar
266282
return;
267283
}
268284

269-
$checkFunction = sprintf('is_%s', $parameter->getType()->getName());
285+
$checkFunction = sprintf('is_%s', $type);
270286

271287
if (!$parameter->getType()->isBuiltin() || !$checkFunction($value)) {
272288
throw new InvalidParameterTypeException($this->currentId, \is_object($value) ? $class : get_debug_type($value), $parameter);

src/Symfony/Component/DependencyInjection/Dumper/Preloader.php

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public static function preload(array $classes): void
6767
}
6868
}
6969

70-
private static function doPreload(string $class, array &$preloaded)
70+
private static function doPreload(string $class, array &$preloaded): void
7171
{
7272
if (isset($preloaded[$class]) || \in_array($class, ['self', 'static', 'parent'], true)) {
7373
return;
@@ -87,9 +87,7 @@ private static function doPreload(string $class, array &$preloaded)
8787

8888
if (\PHP_VERSION_ID >= 70400) {
8989
foreach ($r->getProperties(\ReflectionProperty::IS_PUBLIC) as $p) {
90-
if (($t = $p->getType()) && !$t->isBuiltin()) {
91-
self::doPreload($t->getName(), $preloaded);
92-
}
90+
self::preloadType($p->getType(), $preloaded);
9391
}
9492
}
9593

@@ -103,17 +101,26 @@ private static function doPreload(string $class, array &$preloaded)
103101
}
104102
}
105103

106-
if (($t = $p->getType()) && !$t->isBuiltin()) {
107-
self::doPreload($t->getName(), $preloaded);
108-
}
104+
self::preloadType($p->getType(), $preloaded);
109105
}
110106

111-
if (($t = $m->getReturnType()) && !$t->isBuiltin()) {
112-
self::doPreload($t->getName(), $preloaded);
113-
}
107+
self::preloadType($p->getReturnType(), $preloaded);
114108
}
115109
} catch (\ReflectionException $e) {
116110
// ignore missing classes
117111
}
118112
}
113+
114+
private static function preloadType(?\ReflectionType $t, array &$preloaded): void
115+
{
116+
if (!$t || $t->isBuiltin()) {
117+
return;
118+
}
119+
120+
foreach ($t instanceof \ReflectionUnionType ? $t->getTypes() : [$t] as $t) {
121+
if (!$t->isBuiltin()) {
122+
self::doPreload($t instanceof \ReflectionNamedType ? $t->getName() : $t, $preloaded);
123+
}
124+
}
125+
}
119126
}

src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeException.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ class InvalidParameterTypeException extends InvalidArgumentException
2121
{
2222
public function __construct(string $serviceId, string $type, \ReflectionParameter $parameter)
2323
{
24-
parent::__construct(sprintf('Invalid definition for service "%s": argument %d of "%s::%s" accepts "%s", "%s" passed.', $serviceId, 1 + $parameter->getPosition(), $parameter->getDeclaringClass()->getName(), $parameter->getDeclaringFunction()->getName(), $parameter->getType()->getName(), $type));
24+
$acceptedType = $parameter->getType();
25+
$acceptedType = $acceptedType instanceof \ReflectionNamedType ? $acceptedType->getName() : (string) $acceptedType;
26+
27+
parent::__construct(sprintf('Invalid definition for service "%s": argument %d of "%s::%s" accepts "%s", "%s" passed.', $serviceId, 1 + $parameter->getPosition(), $parameter->getDeclaringClass()->getName(), $parameter->getDeclaringFunction()->getName(), $acceptedType, $type), $type);
2528
}
2629
}

src/Symfony/Component/DependencyInjection/LazyProxy/ProxyHelper.php

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,26 +31,36 @@ public static function getTypeHint(\ReflectionFunctionAbstract $r, \ReflectionPa
3131
if (!$type) {
3232
return null;
3333
}
34-
if (!\is_string($type)) {
35-
$name = $type->getName();
34+
35+
$types = [];
36+
37+
foreach ($type instanceof \ReflectionUnionType ? $type->getTypes() : [$type] as $type) {
38+
$name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type;
3639

3740
if ($type->isBuiltin()) {
38-
return $noBuiltin ? null : $name;
41+
if (!$noBuiltin) {
42+
$types[] = $name;
43+
}
44+
continue;
3945
}
40-
}
41-
$lcName = strtolower($name);
42-
$prefix = $noBuiltin ? '' : '\\';
4346

44-
if ('self' !== $lcName && 'parent' !== $lcName) {
45-
return $prefix.$name;
46-
}
47-
if (!$r instanceof \ReflectionMethod) {
48-
return null;
49-
}
50-
if ('self' === $lcName) {
51-
return $prefix.$r->getDeclaringClass()->name;
47+
$lcName = strtolower($name);
48+
$prefix = $noBuiltin ? '' : '\\';
49+
50+
if ('self' !== $lcName && 'parent' !== $lcName) {
51+
$types[] = '' !== $prefix ? $prefix.$name : $name;
52+
continue;
53+
}
54+
if (!$r instanceof \ReflectionMethod) {
55+
continue;
56+
}
57+
if ('self' === $lcName) {
58+
$types[] = $prefix.$r->getDeclaringClass()->name;
59+
} else {
60+
$types[] = ($parent = $r->getDeclaringClass()->getParentClass()) ? $prefix.$parent->name : null;
61+
}
5262
}
5363

54-
return ($parent = $r->getDeclaringClass()->getParentClass()) ? $prefix.$parent->name : null;
64+
return $types ? implode('|', $types) : null;
5565
}
5666
}

src/Symfony/Component/EventDispatcher/DependencyInjection/RegisterListenersPass.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ private function getEventFromTypeDeclaration(ContainerBuilder $container, string
187187
|| !($r = $container->getReflectionClass($class, false))
188188
|| !$r->hasMethod($method)
189189
|| 1 > ($m = $r->getMethod($method))->getNumberOfParameters()
190-
|| !($type = $m->getParameters()[0]->getType())
190+
|| !($type = $m->getParameters()[0]->getType()) instanceof \ReflectionNamedType
191191
|| $type->isBuiltin()
192192
|| Event::class === ($name = $type->getName())
193193
) {

src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public function createArgumentMetadata($controller): array
4545
*/
4646
private function getType(\ReflectionParameter $parameter, \ReflectionFunctionAbstract $function): ?string
4747
{
48-
if (!$type = $parameter->getType()) {
48+
if (!($type = $parameter->getType()) instanceof \ReflectionNamedType) {
4949
return null;
5050
}
5151
$name = $type->getName();

src/Symfony/Component/HttpKernel/EventListener/ErrorListener.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public function onControllerArguments(ControllerArgumentsEvent $event)
102102
$r = new \ReflectionFunction(\Closure::fromCallable($event->getController()));
103103
$r = $r->getParameters()[$k] ?? null;
104104

105-
if ($r && (!$r->hasType() || \in_array($r->getType()->getName(), [FlattenException::class, LegacyFlattenException::class], true))) {
105+
if ($r && (!($r = $r->getType()) instanceof \ReflectionNamedType || \in_array($r->getName(), [FlattenException::class, LegacyFlattenException::class], true))) {
106106
$arguments = $event->getArguments();
107107
$arguments[$k] = FlattenException::createFromThrowable($e);
108108
$event->setArguments($arguments);

src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,24 @@ private function guessHandledClasses(\ReflectionClass $handlerClass, string $ser
228228
throw new RuntimeException(sprintf('Invalid handler service "%s": argument "$%s" of method "%s::__invoke()" must have a type-hint corresponding to the message class it handles.', $serviceId, $parameters[0]->getName(), $handlerClass->getName()));
229229
}
230230

231+
if ($type instanceof \ReflectionUnionType) {
232+
$types = [];
233+
foreach ($type->getTypes() as $type) {
234+
if (!$type->isBuiltin()) {
235+
$types[] = (string) $type;
236+
}
237+
}
238+
239+
if ($types) {
240+
return $types;
241+
}
242+
}
243+
231244
if ($type->isBuiltin()) {
232245
throw new RuntimeException(sprintf('Invalid handler service "%s": type-hint of argument "$%s" in method "%s::__invoke()" must be a class , "%s" given.', $serviceId, $parameters[0]->getName(), $handlerClass->getName(), $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type));
233246
}
234247

235-
return [$parameters[0]->getType()->getName()];
248+
return [$type->getName()];
236249
}
237250

238251
private function registerReceivers(ContainerBuilder $container, array $busIds)

src/Symfony/Component/OptionsResolver/OptionsResolver.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ public function setDefault(string $option, $value)
206206
return $this;
207207
}
208208

209-
if (isset($params[0]) && null !== ($type = $params[0]->getType()) && self::class === $type->getName() && (!isset($params[1]) || (null !== ($type = $params[1]->getType()) && Options::class === $type->getName()))) {
209+
if (isset($params[0]) && null !== ($type = $params[0]->getType()) && self::class === $type->getName() && (!isset($params[1]) || (($type = $params[1]->getType()) instanceof \ReflectionNamedType && Options::class === $type->getName()))) {
210210
// Store closure for later evaluation
211211
$this->nested[$option][] = $value;
212212
$this->defaults[$option] = [];
@@ -1283,7 +1283,7 @@ private function formatOptions(array $options): string
12831283

12841284
private function getParameterClassName(\ReflectionParameter $parameter): ?string
12851285
{
1286-
if (!($type = $parameter->getType()) || $type->isBuiltin()) {
1286+
if (!($type = $parameter->getType()) instanceof \ReflectionNamedType || $type->isBuiltin()) {
12871287
return null;
12881288
}
12891289

src/Symfony/Component/PropertyAccess/PropertyAccessor.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,8 +428,9 @@ private function readProperty(array $zval, string $property, bool $ignoreInvalid
428428
// handle uninitialized properties in PHP >= 7.4
429429
if (\PHP_VERSION_ID >= 70400 && preg_match('/^Typed property ([\w\\\]+)::\$(\w+) must not be accessed before initialization$/', $e->getMessage(), $matches)) {
430430
$r = new \ReflectionProperty($matches[1], $matches[2]);
431+
$type= ($type = $r->getType()) instanceof \ReflectionNamedType ? $type->getName() : (string) $type;
431432

432-
throw new UninitializedPropertyException(sprintf('The property "%s::$%s" is not readable because it is typed "%s". You should initialize it or declare a default value instead.', $r->getDeclaringClass()->getName(), $r->getName(), $r->getType()->getName()), 0, $e);
433+
throw new UninitializedPropertyException(sprintf('The property "%s::$%s" is not readable because it is typed "%s". You should initialize it or declare a default value instead.', $r->getDeclaringClass()->getName(), $r->getName(), $type, 0, $e);
433434
}
434435

435436
throw $e;

src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ public function getTypes(string $class, string $property, array $context = []):
135135
$reflectionProperty = new \ReflectionProperty($class, $property);
136136
$type = $reflectionProperty->getType();
137137
if (null !== $type) {
138-
return [$this->extractFromReflectionType($type, $reflectionProperty->getDeclaringClass())];
138+
return $this->extractFromReflectionType($type, $reflectionProperty->getDeclaringClass());
139139
}
140140
} catch (\ReflectionException $e) {
141141
// noop
@@ -393,11 +393,11 @@ private function extractFromMutator(string $class, string $property): ?array
393393
}
394394
$type = $this->extractFromReflectionType($reflectionType, $reflectionMethod->getDeclaringClass());
395395

396-
if (\in_array($prefix, $this->arrayMutatorPrefixes)) {
397-
$type = new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $type);
396+
if (1 === \count($type) && \in_array($prefix, $this->arrayMutatorPrefixes)) {
397+
$type = [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $type[0])];
398398
}
399399

400-
return [$type];
400+
return $type;
401401
}
402402

403403
/**
@@ -413,7 +413,7 @@ private function extractFromAccessor(string $class, string $property): ?array
413413
}
414414

415415
if ($reflectionType = $reflectionMethod->getReturnType()) {
416-
return [$this->extractFromReflectionType($reflectionType, $reflectionMethod->getDeclaringClass())];
416+
return $this->extractFromReflectionType($reflectionType, $reflectionMethod->getDeclaringClass());
417417
}
418418

419419
if (\in_array($prefix, ['is', 'can', 'has'])) {
@@ -448,7 +448,7 @@ private function extractFromConstructor(string $class, string $property): ?array
448448
}
449449
$reflectionType = $parameter->getType();
450450

451-
return $reflectionType ? [$this->extractFromReflectionType($reflectionType, $constructor->getDeclaringClass())] : null;
451+
return $reflectionType ? $this->extractFromReflectionType($reflectionType, $constructor->getDeclaringClass()) : null;
452452
}
453453

454454
if ($parentClass = $reflectionClass->getParentClass()) {
@@ -477,22 +477,26 @@ private function extractFromDefaultValue(string $class, string $property): ?arra
477477
return [new Type(static::MAP_TYPES[$type] ?? $type)];
478478
}
479479

480-
private function extractFromReflectionType(\ReflectionType $reflectionType, \ReflectionClass $declaringClass): Type
480+
private function extractFromReflectionType(\ReflectionType $reflectionType, \ReflectionClass $declaringClass): array
481481
{
482-
$phpTypeOrClass = $reflectionType->getName();
482+
$types = [];
483483
$nullable = $reflectionType->allowsNull();
484484

485-
if (Type::BUILTIN_TYPE_ARRAY === $phpTypeOrClass) {
486-
$type = new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true);
487-
} elseif ('void' === $phpTypeOrClass) {
488-
$type = new Type(Type::BUILTIN_TYPE_NULL, $nullable);
489-
} elseif ($reflectionType->isBuiltin()) {
490-
$type = new Type($phpTypeOrClass, $nullable);
491-
} else {
492-
$type = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $this->resolveTypeName($phpTypeOrClass, $declaringClass));
485+
foreach ($reflectionType instanceof \ReflectionUnionType ? $reflectionType->getTypes() : [$reflectionType] as $type) {
486+
$phpTypeOrClass = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : (string) $type;
487+
488+
if (Type::BUILTIN_TYPE_ARRAY === $phpTypeOrClass) {
489+
$types[] = new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true);
490+
} elseif ('void' === $phpTypeOrClass || 'null' === $phpTypeOrClass) {
491+
$types[] = new Type(Type::BUILTIN_TYPE_NULL, $nullable);
492+
} elseif ($reflectionType->isBuiltin()) {
493+
$types[] = new Type($phpTypeOrClass, $nullable);
494+
} else {
495+
$types[] = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $this->resolveTypeName($phpTypeOrClass, $declaringClass));
496+
}
493497
}
494498

495-
return $type;
499+
return $types;
496500
}
497501

498502
private function resolveTypeName(string $name, \ReflectionClass $declaringClass): string

src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ protected function instantiateObject(array &$data, string $class, array &$contex
411411
protected function denormalizeParameter(\ReflectionClass $class, \ReflectionParameter $parameter, string $parameterName, $parameterData, array $context, string $format = null)
412412
{
413413
try {
414-
if (($parameterType = $parameter->getType()) && !$parameterType->isBuiltin()) {
414+
if (($parameterType = $parameter->getType()) instanceof \ReflectionNamedType && !$parameterType->isBuiltin()) {
415415
$parameterClass = $parameterType->getName();
416416
new \ReflectionClass($parameterClass); // throws a \ReflectionException if the class doesn't exist
417417

0 commit comments

Comments
 (0)