[3.4] Fix support for PHP8 union types
This commit is contained in:
parent
57251cdcdd
commit
e09372bcbf
@ -177,6 +177,7 @@ class ReflectionClassResource implements SelfCheckingResourceInterface, \Seriali
|
||||
if (!$parametersWithUndefinedConstants) {
|
||||
yield preg_replace('/^ @@.*/m', '', $m);
|
||||
} else {
|
||||
$t = \PHP_VERSION_ID >= 70000 ? $m->getReturnType() : '';
|
||||
$stack = [
|
||||
$m->getDocComment(),
|
||||
$m->getName(),
|
||||
@ -187,15 +188,16 @@ class ReflectionClassResource implements SelfCheckingResourceInterface, \Seriali
|
||||
$m->isPrivate(),
|
||||
$m->isProtected(),
|
||||
$m->returnsReference(),
|
||||
\PHP_VERSION_ID >= 70000 && $m->hasReturnType() ? (\PHP_VERSION_ID >= 70100 ? $m->getReturnType()->getName() : (string) $m->getReturnType()) : '',
|
||||
$t instanceof \ReflectionNamedType ? ((string) $t->allowsNull()).$t->getName() : (string) $t,
|
||||
];
|
||||
|
||||
foreach ($m->getParameters() as $p) {
|
||||
if (!isset($parametersWithUndefinedConstants[$p->name])) {
|
||||
$stack[] = (string) $p;
|
||||
} else {
|
||||
$t = \PHP_VERSION_ID >= 70000 ? $p->getType() : '';
|
||||
$stack[] = $p->isOptional();
|
||||
$stack[] = \PHP_VERSION_ID >= 70000 && $p->hasType() ? (\PHP_VERSION_ID >= 70100 ? $p->getType()->getName() : (string) $p->getType()) : '';
|
||||
$stack[] = $t instanceof \ReflectionNamedType ? $t->getName() : (string) $t;
|
||||
$stack[] = $p->isPassedByReference();
|
||||
$stack[] = \PHP_VERSION_ID >= 50600 ? $p->isVariadic() : '';
|
||||
$stack[] = $p->getName();
|
||||
|
@ -39,26 +39,36 @@ class ProxyHelper
|
||||
if (!$type) {
|
||||
return null;
|
||||
}
|
||||
if (!\is_string($type)) {
|
||||
$name = $type instanceof \ReflectionNamedType ? $type->getName() : $type->__toString();
|
||||
|
||||
if ($type->isBuiltin()) {
|
||||
return $noBuiltin ? null : $name;
|
||||
$types = [];
|
||||
|
||||
foreach ($type instanceof \ReflectionUnionType ? $type->getTypes() : [$type] as $type) {
|
||||
$name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type;
|
||||
|
||||
if (!\is_string($type) && $type->isBuiltin()) {
|
||||
if (!$noBuiltin) {
|
||||
$types[] = $name;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$lcName = strtolower($name);
|
||||
$prefix = $noBuiltin ? '' : '\\';
|
||||
|
||||
if ('self' !== $lcName && 'parent' !== $lcName) {
|
||||
$types[] = '' !== $prefix ? $prefix.$name : $name;
|
||||
continue;
|
||||
}
|
||||
if (!$r instanceof \ReflectionMethod) {
|
||||
continue;
|
||||
}
|
||||
if ('self' === $lcName) {
|
||||
$types[] = $prefix.$r->getDeclaringClass()->name;
|
||||
} else {
|
||||
$types[] = ($parent = $r->getDeclaringClass()->getParentClass()) ? $prefix.$parent->name : null;
|
||||
}
|
||||
}
|
||||
$lcName = strtolower($name);
|
||||
$prefix = $noBuiltin ? '' : '\\';
|
||||
|
||||
if ('self' !== $lcName && 'parent' !== $lcName) {
|
||||
return $prefix.$name;
|
||||
}
|
||||
if (!$r instanceof \ReflectionMethod) {
|
||||
return null;
|
||||
}
|
||||
if ('self' === $lcName) {
|
||||
return $prefix.$r->getDeclaringClass()->name;
|
||||
}
|
||||
|
||||
return ($parent = $r->getDeclaringClass()->getParentClass()) ? $prefix.$parent->name : null;
|
||||
return $types ? implode('|', $types) : null;
|
||||
}
|
||||
}
|
||||
|
@ -1076,7 +1076,7 @@ class OptionsResolver implements Options
|
||||
return ($class = $parameter->getClass()) ? $class->name : null;
|
||||
}
|
||||
|
||||
if (!($type = $parameter->getType()) || $type->isBuiltin()) {
|
||||
if (!($type = $parameter->getType()) instanceof \ReflectionNamedType || $type->isBuiltin()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -519,8 +519,9 @@ class PropertyAccessor implements PropertyAccessorInterface
|
||||
// handle uninitialized properties in PHP >= 7.4
|
||||
if (\PHP_VERSION_ID >= 70400 && preg_match('/^Typed property ([\w\\\]+)::\$(\w+) must not be accessed before initialization$/', $e->getMessage(), $matches)) {
|
||||
$r = new \ReflectionProperty($matches[1], $matches[2]);
|
||||
$type = ($type = $r->getType()) instanceof \ReflectionNamedType ? $type->getName() : (string) $type;
|
||||
|
||||
throw new AccessException(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);
|
||||
throw new AccessException(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);
|
||||
}
|
||||
|
||||
throw $e;
|
||||
|
@ -187,26 +187,26 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp
|
||||
$type = $this->extractFromReflectionType($reflectionType, $reflectionMethod);
|
||||
|
||||
// HHVM reports variadics with "array" but not builtin type hints
|
||||
if (!$reflectionType->isBuiltin() && Type::BUILTIN_TYPE_ARRAY === $type->getBuiltinType()) {
|
||||
if (1 === \count($type) && !$reflectionType->isBuiltin() && Type::BUILTIN_TYPE_ARRAY === $type[0]->getBuiltinType()) {
|
||||
return null;
|
||||
}
|
||||
} elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $reflectionParameter, $info)) {
|
||||
if (Type::BUILTIN_TYPE_ARRAY === $info[1]) {
|
||||
$type = new Type(Type::BUILTIN_TYPE_ARRAY, $reflectionParameter->allowsNull(), null, true);
|
||||
$type = [new Type(Type::BUILTIN_TYPE_ARRAY, $reflectionParameter->allowsNull(), null, true)];
|
||||
} elseif (Type::BUILTIN_TYPE_CALLABLE === $info[1]) {
|
||||
$type = new Type(Type::BUILTIN_TYPE_CALLABLE, $reflectionParameter->allowsNull());
|
||||
$type = [new Type(Type::BUILTIN_TYPE_CALLABLE, $reflectionParameter->allowsNull())];
|
||||
} else {
|
||||
$type = new Type(Type::BUILTIN_TYPE_OBJECT, $reflectionParameter->allowsNull(), $this->resolveTypeName($info[1], $reflectionMethod));
|
||||
$type = [new Type(Type::BUILTIN_TYPE_OBJECT, $reflectionParameter->allowsNull(), $this->resolveTypeName($info[1], $reflectionMethod))];
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (\in_array($prefix, $this->arrayMutatorPrefixes)) {
|
||||
$type = new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $type);
|
||||
if (1 === \count($type) && \in_array($prefix, $this->arrayMutatorPrefixes)) {
|
||||
$type = [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $type[0])];
|
||||
}
|
||||
|
||||
return [$type];
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -225,7 +225,7 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp
|
||||
}
|
||||
|
||||
if ($this->supportsParameterType && $reflectionType = $reflectionMethod->getReturnType()) {
|
||||
return [$this->extractFromReflectionType($reflectionType, $reflectionMethod)];
|
||||
return $this->extractFromReflectionType($reflectionType, $reflectionMethod);
|
||||
}
|
||||
|
||||
return \in_array($prefix, ['is', 'can']) ? [new Type(Type::BUILTIN_TYPE_BOOL)] : null;
|
||||
@ -234,24 +234,28 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp
|
||||
/**
|
||||
* Extracts data from the PHP 7 reflection type.
|
||||
*
|
||||
* @return Type
|
||||
* @return Type[]
|
||||
*/
|
||||
private function extractFromReflectionType(\ReflectionType $reflectionType, \ReflectionMethod $reflectionMethod)
|
||||
{
|
||||
$phpTypeOrClass = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : $reflectionType->__toString();
|
||||
$types = [];
|
||||
$nullable = $reflectionType->allowsNull();
|
||||
|
||||
if (Type::BUILTIN_TYPE_ARRAY === $phpTypeOrClass) {
|
||||
$type = new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true);
|
||||
} elseif ('void' === $phpTypeOrClass) {
|
||||
$type = new Type(Type::BUILTIN_TYPE_NULL, $nullable);
|
||||
} elseif ($reflectionType->isBuiltin()) {
|
||||
$type = new Type($phpTypeOrClass, $nullable);
|
||||
} else {
|
||||
$type = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $this->resolveTypeName($phpTypeOrClass, $reflectionMethod));
|
||||
foreach ($reflectionType instanceof \ReflectionUnionType ? $reflectionType->getTypes() : [$reflectionType] as $type) {
|
||||
$phpTypeOrClass = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : (string) $type;
|
||||
|
||||
if (Type::BUILTIN_TYPE_ARRAY === $phpTypeOrClass) {
|
||||
$types[] = new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true);
|
||||
} elseif ('void' === $phpTypeOrClass || 'null' === $phpTypeOrClass) {
|
||||
$types[] = new Type(Type::BUILTIN_TYPE_NULL, $nullable);
|
||||
} elseif ($reflectionType->isBuiltin()) {
|
||||
$types[] = new Type($phpTypeOrClass, $nullable);
|
||||
} else {
|
||||
$types[] = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $this->resolveTypeName($phpTypeOrClass, $reflectionMethod));
|
||||
}
|
||||
}
|
||||
|
||||
return $type;
|
||||
return $types;
|
||||
}
|
||||
|
||||
private function resolveTypeName($name, \ReflectionMethod $reflectionMethod)
|
||||
|
@ -388,7 +388,7 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N
|
||||
try {
|
||||
if (\PHP_VERSION_ID < 70100 && null !== $parameterClass = $parameter->getClass()) {
|
||||
$parameterClass = $parameterClass->name;
|
||||
} elseif (\PHP_VERSION_ID >= 70100 && ($parameterType = $parameter->getType()) && !$parameterType->isBuiltin()) {
|
||||
} elseif (\PHP_VERSION_ID >= 70100 && ($parameterType = $parameter->getType()) instanceof \ReflectionNamedType && !$parameterType->isBuiltin()) {
|
||||
$parameterClass = $parameterType->getName();
|
||||
new \ReflectionClass($parameterClass); // throws a \ReflectionException if the class doesn't exist
|
||||
} else {
|
||||
|
@ -91,7 +91,7 @@ class ReflectionCaster
|
||||
$prefix = Caster::PREFIX_VIRTUAL;
|
||||
|
||||
$a += [
|
||||
$prefix.'name' => $c instanceof \ReflectionNamedType ? $c->getName() : $c->__toString(),
|
||||
$prefix.'name' => $c instanceof \ReflectionNamedType ? $c->getName() : (string) $c,
|
||||
$prefix.'allowsNull' => $c->allowsNull(),
|
||||
$prefix.'isBuiltin' => $c->isBuiltin(),
|
||||
];
|
||||
@ -178,7 +178,7 @@ class ReflectionCaster
|
||||
|
||||
if (isset($a[$prefix.'returnType'])) {
|
||||
$v = $a[$prefix.'returnType'];
|
||||
$v = $v instanceof \ReflectionNamedType ? $v->getName() : $v->__toString();
|
||||
$v = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v;
|
||||
$a[$prefix.'returnType'] = new ClassStub($a[$prefix.'returnType']->allowsNull() ? '?'.$v : $v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']);
|
||||
}
|
||||
if (isset($a[$prefix.'class'])) {
|
||||
@ -247,7 +247,7 @@ class ReflectionCaster
|
||||
|
||||
if (method_exists($c, 'getType')) {
|
||||
if ($v = $c->getType()) {
|
||||
$a[$prefix.'typeHint'] = $v instanceof \ReflectionNamedType ? $v->getName() : $v->__toString();
|
||||
$a[$prefix.'typeHint'] = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v;
|
||||
}
|
||||
} elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $c, $v)) {
|
||||
$a[$prefix.'typeHint'] = $v[1];
|
||||
|
Reference in New Issue
Block a user