From ed98c127027849c75d74ee3f2d3dcba5e46b7a25 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Mon, 20 Sep 2021 01:23:10 +0200 Subject: [PATCH] Reflection: getReturnType(), getParameterType(), getPropertyType() return objects Type (BC break) --- src/Utils/Reflection.php | 33 +++------------ .../Utils/Reflection.getParameterType.81.phpt | 31 +++++--------- tests/Utils/Reflection.getParameterType.phpt | 25 ++++------- .../Utils/Reflection.getPropertyType.81.phpt | 29 ++++--------- tests/Utils/Reflection.getPropertyType.phpt | 23 ++++------ tests/Utils/Reflection.getReturnType.81.phpt | 42 +++++++------------ tests/Utils/Reflection.getReturnType.phpt | 32 ++++++-------- 7 files changed, 69 insertions(+), 146 deletions(-) diff --git a/src/Utils/Reflection.php b/src/Utils/Reflection.php index cb1c10beb..bdfa47fc4 100644 --- a/src/Utils/Reflection.php +++ b/src/Utils/Reflection.php @@ -51,51 +51,30 @@ public static function isClassKeyword(string $name): bool /** * Returns the type of return value of given function or method and normalizes `self`, `static`, and `parent` to actual class names. * If the function does not have a return type, it returns null. - * If the function has union or intersection type, it throws Nette\InvalidStateException. */ - public static function getReturnType(\ReflectionFunctionAbstract $func): ?string + public static function getReturnType(\ReflectionFunctionAbstract $func): ?Type { - $type = $func->getReturnType() ?? (PHP_VERSION_ID >= 80100 && $func instanceof \ReflectionMethod ? $func->getTentativeReturnType() : null); - return self::getType($func, $type); + return Type::fromReflection($func); } /** * Returns the type of given parameter and normalizes `self` and `parent` to the actual class names. * If the parameter does not have a type, it returns null. - * If the parameter has union or intersection type, it throws Nette\InvalidStateException. */ - public static function getParameterType(\ReflectionParameter $param): ?string + public static function getParameterType(\ReflectionParameter $param): ?Type { - return self::getType($param, $param->getType()); + return Type::fromReflection($param); } /** * Returns the type of given property and normalizes `self` and `parent` to the actual class names. * If the property does not have a type, it returns null. - * If the property has union or intersection type, it throws Nette\InvalidStateException. */ - public static function getPropertyType(\ReflectionProperty $prop): ?string + public static function getPropertyType(\ReflectionProperty $prop): ?Type { - return self::getType($prop, $prop->getType()); - } - - - private static function getType(\ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionProperty $reflection, ?\ReflectionType $type): ?string - { - if ($type === null) { - return null; - - } elseif ($type instanceof \ReflectionNamedType) { - return Type::resolve($type->getName(), $reflection); - - } elseif ($type instanceof \ReflectionUnionType || $type instanceof \ReflectionIntersectionType) { - throw new Nette\InvalidStateException('The ' . self::toString($reflection) . ' is not expected to have a union or intersection type.'); - - } else { - throw new Nette\InvalidStateException('Unexpected type of ' . self::toString($reflection)); - } + return Type::fromReflection($prop); } diff --git a/tests/Utils/Reflection.getParameterType.81.phpt b/tests/Utils/Reflection.getParameterType.81.phpt index 15d75986f..5adb2643c 100644 --- a/tests/Utils/Reflection.getParameterType.81.phpt +++ b/tests/Utils/Reflection.getParameterType.81.phpt @@ -43,28 +43,17 @@ class AExt extends A $method = new ReflectionMethod('A', 'method'); $params = $method->getParameters(); -Assert::same('Undeclared', Reflection::getParameterType($params[0])); -Assert::same('Test\B', Reflection::getParameterType($params[1])); -Assert::same('array', Reflection::getParameterType($params[2])); -Assert::same('callable', Reflection::getParameterType($params[3])); -Assert::same('A', Reflection::getParameterType($params[4])); +Assert::same('Undeclared', (string) Reflection::getParameterType($params[0])); +Assert::same('Test\B', (string) Reflection::getParameterType($params[1])); +Assert::same('array', (string) Reflection::getParameterType($params[2])); +Assert::same('callable', (string) Reflection::getParameterType($params[3])); +Assert::same('A', (string) Reflection::getParameterType($params[4])); Assert::null(Reflection::getParameterType($params[5])); -Assert::same('Test\B', Reflection::getParameterType($params[6])); -Assert::same('mixed', Reflection::getParameterType($params[7])); - -Assert::exception(function () use ($params) { - Reflection::getParameterType($params[8]); -}, Nette\InvalidStateException::class, 'The $union in A::method() is not expected to have a union or intersection type.'); - -Assert::exception(function () use ($params) { - Reflection::getParameterType($params[9]); -}, Nette\InvalidStateException::class, 'The $nullableUnion in A::method() is not expected to have a union or intersection type.'); - -Assert::exception(function () use ($params) { - Reflection::getParameterType($params[10]); -}, Nette\InvalidStateException::class, 'The $intersection in A::method() is not expected to have a union or intersection type.'); - +Assert::same('?Test\B', (string) Reflection::getParameterType($params[6])); +Assert::same('mixed', (string) Reflection::getParameterType($params[7])); +Assert::same('A|array', (string) Reflection::getParameterType($params[8], false)); +Assert::same('A|array|null', (string) Reflection::getParameterType($params[9], false)); $method = new ReflectionMethod('AExt', 'methodExt'); $params = $method->getParameters(); -Assert::same('A', Reflection::getParameterType($params[0])); +Assert::same('A', (string) Reflection::getParameterType($params[0])); diff --git a/tests/Utils/Reflection.getParameterType.phpt b/tests/Utils/Reflection.getParameterType.phpt index 9e00ed6d9..616c67325 100644 --- a/tests/Utils/Reflection.getParameterType.phpt +++ b/tests/Utils/Reflection.getParameterType.phpt @@ -41,25 +41,16 @@ class AExt extends A $method = new ReflectionMethod('A', 'method'); $params = $method->getParameters(); -Assert::same('Undeclared', Reflection::getParameterType($params[0])); -Assert::same('Test\B', Reflection::getParameterType($params[1])); -Assert::same('array', Reflection::getParameterType($params[2])); -Assert::same('callable', Reflection::getParameterType($params[3])); -Assert::same('A', Reflection::getParameterType($params[4])); +Assert::same('Undeclared', (string) Reflection::getParameterType($params[0])); +Assert::same('Test\B', (string) Reflection::getParameterType($params[1])); +Assert::same('array', (string) Reflection::getParameterType($params[2])); +Assert::same('callable', (string) Reflection::getParameterType($params[3])); +Assert::same('A', (string) Reflection::getParameterType($params[4])); Assert::null(Reflection::getParameterType($params[5])); -Assert::same('Test\B', Reflection::getParameterType($params[6])); -Assert::same('mixed', Reflection::getParameterType($params[7])); - -Assert::exception(function () use ($params) { - Reflection::getParameterType($params[8]); -}, Nette\InvalidStateException::class, 'The $union in A::method() is not expected to have a union or intersection type.'); - -Assert::exception(function () use ($params) { - Reflection::getParameterType($params[9]); -}, Nette\InvalidStateException::class, 'The $nullableUnion in A::method() is not expected to have a union or intersection type.'); - +Assert::same('?Test\B', (string) Reflection::getParameterType($params[6])); +Assert::same('mixed', (string) Reflection::getParameterType($params[7])); $method = new ReflectionMethod('AExt', 'methodExt'); $params = $method->getParameters(); -Assert::same('A', Reflection::getParameterType($params[0])); +Assert::same('A', (string) Reflection::getParameterType($params[0])); diff --git a/tests/Utils/Reflection.getPropertyType.81.phpt b/tests/Utils/Reflection.getPropertyType.81.phpt index d7905d6d6..38d42c4e0 100644 --- a/tests/Utils/Reflection.getPropertyType.81.phpt +++ b/tests/Utils/Reflection.getPropertyType.81.phpt @@ -37,27 +37,16 @@ class AExt extends A $class = new ReflectionClass('A'); $props = $class->getProperties(); -Assert::same('Undeclared', Reflection::getPropertyType($props[0])); -Assert::same('Test\B', Reflection::getPropertyType($props[1])); -Assert::same('array', Reflection::getPropertyType($props[2])); -Assert::same('A', Reflection::getPropertyType($props[3])); +Assert::same('Undeclared', (string) Reflection::getPropertyType($props[0])); +Assert::same('Test\B', (string) Reflection::getPropertyType($props[1])); +Assert::same('array', (string) Reflection::getPropertyType($props[2])); +Assert::same('A', (string) Reflection::getPropertyType($props[3])); Assert::null(Reflection::getPropertyType($props[4])); -Assert::same('Test\B', Reflection::getPropertyType($props[5])); -Assert::same('mixed', Reflection::getPropertyType($props[6])); - -Assert::exception(function () use ($props) { - Reflection::getPropertyType($props[7]); -}, Nette\InvalidStateException::class, 'The A::$union is not expected to have a union or intersection type.'); - -Assert::exception(function () use ($props) { - Reflection::getPropertyType($props[8]); -}, Nette\InvalidStateException::class, 'The A::$nullableUnion is not expected to have a union or intersection type.'); - -Assert::exception(function () use ($props) { - Reflection::getPropertyType($props[9]); -}, Nette\InvalidStateException::class, 'The A::$intersection is not expected to have a union or intersection type.'); - +Assert::same('?Test\B', (string) Reflection::getPropertyType($props[5])); +Assert::same('mixed', (string) Reflection::getPropertyType($props[6])); +Assert::same('A|array', (string) Reflection::getPropertyType($props[7], false)); +Assert::same('A|array|null', (string) Reflection::getPropertyType($props[8], false)); $class = new ReflectionClass('AExt'); $props = $class->getProperties(); -Assert::same('A', Reflection::getPropertyType($props[0])); +Assert::same('A', (string) Reflection::getPropertyType($props[0])); diff --git a/tests/Utils/Reflection.getPropertyType.phpt b/tests/Utils/Reflection.getPropertyType.phpt index 161e4ac7e..44abc0630 100644 --- a/tests/Utils/Reflection.getPropertyType.phpt +++ b/tests/Utils/Reflection.getPropertyType.phpt @@ -35,23 +35,14 @@ class AExt extends A $class = new ReflectionClass('A'); $props = $class->getProperties(); -Assert::same('Undeclared', Reflection::getPropertyType($props[0])); -Assert::same('Test\B', Reflection::getPropertyType($props[1])); -Assert::same('array', Reflection::getPropertyType($props[2])); -Assert::same('A', Reflection::getPropertyType($props[3])); +Assert::same('Undeclared', (string) Reflection::getPropertyType($props[0])); +Assert::same('Test\B', (string) Reflection::getPropertyType($props[1])); +Assert::same('array', (string) Reflection::getPropertyType($props[2])); +Assert::same('A', (string) Reflection::getPropertyType($props[3])); Assert::null(Reflection::getPropertyType($props[4])); -Assert::same('Test\B', Reflection::getPropertyType($props[5])); -Assert::same('mixed', Reflection::getPropertyType($props[6])); - -Assert::exception(function () use ($props) { - Reflection::getPropertyType($props[7]); -}, Nette\InvalidStateException::class, 'The A::$union is not expected to have a union or intersection type.'); - -Assert::exception(function () use ($props) { - Reflection::getPropertyType($props[8]); -}, Nette\InvalidStateException::class, 'The A::$nullableUnion is not expected to have a union or intersection type.'); - +Assert::same('?Test\B', (string) Reflection::getPropertyType($props[5])); +Assert::same('mixed', (string) Reflection::getPropertyType($props[6])); $class = new ReflectionClass('AExt'); $props = $class->getProperties(); -Assert::same('A', Reflection::getPropertyType($props[0])); +Assert::same('A', (string) Reflection::getPropertyType($props[0])); diff --git a/tests/Utils/Reflection.getReturnType.81.phpt b/tests/Utils/Reflection.getReturnType.81.phpt index 704c55dff..c0b8cfb57 100644 --- a/tests/Utils/Reflection.getReturnType.81.phpt +++ b/tests/Utils/Reflection.getReturnType.81.phpt @@ -106,48 +106,38 @@ function intersectionType(): AExt&A Assert::null(Reflection::getReturnType(new \ReflectionMethod(A::class, 'noType'))); -Assert::same('Test\B', Reflection::getReturnType(new \ReflectionMethod(A::class, 'classType'))); +Assert::same('Test\B', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'classType'))); -Assert::same('string', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nativeType'))); +Assert::same('string', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nativeType'))); -Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(A::class, 'selfType'))); +Assert::same('A', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'selfType'))); -Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(A::class, 'staticType'))); +Assert::same('A', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'staticType'))); -Assert::same('Test\B', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableClassType'))); +Assert::same('?Test\B', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableClassType'))); -Assert::same('string', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableNativeType'))); +Assert::same('?string', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableNativeType'))); -Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableSelfType'))); +Assert::same('?A', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableSelfType'))); -Assert::exception(function () { - Reflection::getReturnType(new \ReflectionMethod(A::class, 'unionType')); -}, Nette\InvalidStateException::class, 'The A::unionType() is not expected to have a union or intersection type.'); +Assert::same('A|array', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'unionType'))); -Assert::exception(function () { - Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableUnionType')); -}, Nette\InvalidStateException::class, 'The A::nullableUnionType() is not expected to have a union or intersection type.'); +Assert::same('A|array|null', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableUnionType'))); -Assert::exception(function () { - Reflection::getReturnType(new \ReflectionMethod(A::class, 'intersectionType')); -}, Nette\InvalidStateException::class, 'The A::intersectionType() is not expected to have a union or intersection type.'); +Assert::same('AExt&A', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'intersectionType'))); -Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(AExt::class, 'parentTypeExt'))); +Assert::same('A', (string) Reflection::getReturnType(new \ReflectionMethod(AExt::class, 'parentTypeExt'))); Assert::null(Reflection::getReturnType(new \ReflectionFunction('noType'))); -Assert::same('Test\B', Reflection::getReturnType(new \ReflectionFunction('classType'))); +Assert::same('Test\B', (string) Reflection::getReturnType(new \ReflectionFunction('classType'))); -Assert::same('string', Reflection::getReturnType(new \ReflectionFunction('nativeType'))); +Assert::same('string', (string) Reflection::getReturnType(new \ReflectionFunction('nativeType'))); -Assert::exception(function () { - Reflection::getReturnType(new \ReflectionFunction('unionType')); -}, Nette\InvalidStateException::class, 'The unionType() is not expected to have a union or intersection type.'); +Assert::same('A|array', (string) Reflection::getReturnType(new \ReflectionFunction('unionType'))); -Assert::exception(function () { - Reflection::getReturnType(new \ReflectionFunction('intersectionType')); -}, Nette\InvalidStateException::class, 'The intersectionType() is not expected to have a union or intersection type.'); +Assert::same('AExt&A', (string) Reflection::getReturnType(new \ReflectionFunction('intersectionType'))); // tentative type -Assert::same('int', Reflection::getReturnType(new \ReflectionMethod(\ArrayObject::class, 'count'))); +Assert::same('int', (string) Reflection::getReturnType(new \ReflectionMethod(\ArrayObject::class, 'count'))); diff --git a/tests/Utils/Reflection.getReturnType.phpt b/tests/Utils/Reflection.getReturnType.phpt index 351d098c4..e4002c5dd 100644 --- a/tests/Utils/Reflection.getReturnType.phpt +++ b/tests/Utils/Reflection.getReturnType.phpt @@ -95,36 +95,30 @@ function unionType(): array|A Assert::null(Reflection::getReturnType(new \ReflectionMethod(A::class, 'noType'))); -Assert::same('Test\B', Reflection::getReturnType(new \ReflectionMethod(A::class, 'classType'))); +Assert::same('Test\B', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'classType'))); -Assert::same('string', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nativeType'))); +Assert::same('string', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nativeType'))); -Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(A::class, 'selfType'))); +Assert::same('A', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'selfType'))); -Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(A::class, 'staticType'))); +Assert::same('A', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'staticType'))); -Assert::same('Test\B', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableClassType'))); +Assert::same('?Test\B', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableClassType'))); -Assert::same('string', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableNativeType'))); +Assert::same('?string', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableNativeType'))); -Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableSelfType'))); +Assert::same('?A', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableSelfType'))); -Assert::exception(function () { - Reflection::getReturnType(new \ReflectionMethod(A::class, 'unionType')); -}, Nette\InvalidStateException::class, 'The A::unionType() is not expected to have a union or intersection type.'); +Assert::same('A|array', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'unionType'))); -Assert::exception(function () { - Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableUnionType')); -}, Nette\InvalidStateException::class, 'The A::nullableUnionType() is not expected to have a union or intersection type.'); +Assert::same('A|array|null', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableUnionType'))); -Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(AExt::class, 'parentTypeExt'))); +Assert::same('A', (string) Reflection::getReturnType(new \ReflectionMethod(AExt::class, 'parentTypeExt'))); Assert::null(Reflection::getReturnType(new \ReflectionFunction('noType'))); -Assert::same('Test\B', Reflection::getReturnType(new \ReflectionFunction('classType'))); +Assert::same('Test\B', (string) Reflection::getReturnType(new \ReflectionFunction('classType'))); -Assert::same('string', Reflection::getReturnType(new \ReflectionFunction('nativeType'))); +Assert::same('string', (string) Reflection::getReturnType(new \ReflectionFunction('nativeType'))); -Assert::exception(function () { - Reflection::getReturnType(new \ReflectionFunction('unionType')); -}, Nette\InvalidStateException::class, 'The unionType() is not expected to have a union or intersection type.'); +Assert::same('A|array', (string) Reflection::getReturnType(new \ReflectionFunction('unionType')));