Skip to content

Commit ed98c12

Browse files
committed
Reflection: getReturnType(), getParameterType(), getPropertyType() return objects Type (BC break)
1 parent 29e8256 commit ed98c12

7 files changed

+69
-146
lines changed

src/Utils/Reflection.php

+6-27
Original file line numberDiff line numberDiff line change
@@ -51,51 +51,30 @@ public static function isClassKeyword(string $name): bool
5151
/**
5252
* Returns the type of return value of given function or method and normalizes `self`, `static`, and `parent` to actual class names.
5353
* If the function does not have a return type, it returns null.
54-
* If the function has union or intersection type, it throws Nette\InvalidStateException.
5554
*/
56-
public static function getReturnType(\ReflectionFunctionAbstract $func): ?string
55+
public static function getReturnType(\ReflectionFunctionAbstract $func): ?Type
5756
{
58-
$type = $func->getReturnType() ?? (PHP_VERSION_ID >= 80100 && $func instanceof \ReflectionMethod ? $func->getTentativeReturnType() : null);
59-
return self::getType($func, $type);
57+
return Type::fromReflection($func);
6058
}
6159

6260

6361
/**
6462
* Returns the type of given parameter and normalizes `self` and `parent` to the actual class names.
6563
* If the parameter does not have a type, it returns null.
66-
* If the parameter has union or intersection type, it throws Nette\InvalidStateException.
6764
*/
68-
public static function getParameterType(\ReflectionParameter $param): ?string
65+
public static function getParameterType(\ReflectionParameter $param): ?Type
6966
{
70-
return self::getType($param, $param->getType());
67+
return Type::fromReflection($param);
7168
}
7269

7370

7471
/**
7572
* Returns the type of given property and normalizes `self` and `parent` to the actual class names.
7673
* If the property does not have a type, it returns null.
77-
* If the property has union or intersection type, it throws Nette\InvalidStateException.
7874
*/
79-
public static function getPropertyType(\ReflectionProperty $prop): ?string
75+
public static function getPropertyType(\ReflectionProperty $prop): ?Type
8076
{
81-
return self::getType($prop, $prop->getType());
82-
}
83-
84-
85-
private static function getType(\ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionProperty $reflection, ?\ReflectionType $type): ?string
86-
{
87-
if ($type === null) {
88-
return null;
89-
90-
} elseif ($type instanceof \ReflectionNamedType) {
91-
return Type::resolve($type->getName(), $reflection);
92-
93-
} elseif ($type instanceof \ReflectionUnionType || $type instanceof \ReflectionIntersectionType) {
94-
throw new Nette\InvalidStateException('The ' . self::toString($reflection) . ' is not expected to have a union or intersection type.');
95-
96-
} else {
97-
throw new Nette\InvalidStateException('Unexpected type of ' . self::toString($reflection));
98-
}
77+
return Type::fromReflection($prop);
9978
}
10079

10180

tests/Utils/Reflection.getParameterType.81.phpt

+10-21
Original file line numberDiff line numberDiff line change
@@ -43,28 +43,17 @@ class AExt extends A
4343
$method = new ReflectionMethod('A', 'method');
4444
$params = $method->getParameters();
4545

46-
Assert::same('Undeclared', Reflection::getParameterType($params[0]));
47-
Assert::same('Test\B', Reflection::getParameterType($params[1]));
48-
Assert::same('array', Reflection::getParameterType($params[2]));
49-
Assert::same('callable', Reflection::getParameterType($params[3]));
50-
Assert::same('A', Reflection::getParameterType($params[4]));
46+
Assert::same('Undeclared', (string) Reflection::getParameterType($params[0]));
47+
Assert::same('Test\B', (string) Reflection::getParameterType($params[1]));
48+
Assert::same('array', (string) Reflection::getParameterType($params[2]));
49+
Assert::same('callable', (string) Reflection::getParameterType($params[3]));
50+
Assert::same('A', (string) Reflection::getParameterType($params[4]));
5151
Assert::null(Reflection::getParameterType($params[5]));
52-
Assert::same('Test\B', Reflection::getParameterType($params[6]));
53-
Assert::same('mixed', Reflection::getParameterType($params[7]));
54-
55-
Assert::exception(function () use ($params) {
56-
Reflection::getParameterType($params[8]);
57-
}, Nette\InvalidStateException::class, 'The $union in A::method() is not expected to have a union or intersection type.');
58-
59-
Assert::exception(function () use ($params) {
60-
Reflection::getParameterType($params[9]);
61-
}, Nette\InvalidStateException::class, 'The $nullableUnion in A::method() is not expected to have a union or intersection type.');
62-
63-
Assert::exception(function () use ($params) {
64-
Reflection::getParameterType($params[10]);
65-
}, Nette\InvalidStateException::class, 'The $intersection in A::method() is not expected to have a union or intersection type.');
66-
52+
Assert::same('?Test\B', (string) Reflection::getParameterType($params[6]));
53+
Assert::same('mixed', (string) Reflection::getParameterType($params[7]));
54+
Assert::same('A|array', (string) Reflection::getParameterType($params[8], false));
55+
Assert::same('A|array|null', (string) Reflection::getParameterType($params[9], false));
6756
$method = new ReflectionMethod('AExt', 'methodExt');
6857
$params = $method->getParameters();
6958

70-
Assert::same('A', Reflection::getParameterType($params[0]));
59+
Assert::same('A', (string) Reflection::getParameterType($params[0]));

tests/Utils/Reflection.getParameterType.phpt

+8-17
Original file line numberDiff line numberDiff line change
@@ -41,25 +41,16 @@ class AExt extends A
4141
$method = new ReflectionMethod('A', 'method');
4242
$params = $method->getParameters();
4343

44-
Assert::same('Undeclared', Reflection::getParameterType($params[0]));
45-
Assert::same('Test\B', Reflection::getParameterType($params[1]));
46-
Assert::same('array', Reflection::getParameterType($params[2]));
47-
Assert::same('callable', Reflection::getParameterType($params[3]));
48-
Assert::same('A', Reflection::getParameterType($params[4]));
44+
Assert::same('Undeclared', (string) Reflection::getParameterType($params[0]));
45+
Assert::same('Test\B', (string) Reflection::getParameterType($params[1]));
46+
Assert::same('array', (string) Reflection::getParameterType($params[2]));
47+
Assert::same('callable', (string) Reflection::getParameterType($params[3]));
48+
Assert::same('A', (string) Reflection::getParameterType($params[4]));
4949
Assert::null(Reflection::getParameterType($params[5]));
50-
Assert::same('Test\B', Reflection::getParameterType($params[6]));
51-
Assert::same('mixed', Reflection::getParameterType($params[7]));
52-
53-
Assert::exception(function () use ($params) {
54-
Reflection::getParameterType($params[8]);
55-
}, Nette\InvalidStateException::class, 'The $union in A::method() is not expected to have a union or intersection type.');
56-
57-
Assert::exception(function () use ($params) {
58-
Reflection::getParameterType($params[9]);
59-
}, Nette\InvalidStateException::class, 'The $nullableUnion in A::method() is not expected to have a union or intersection type.');
60-
50+
Assert::same('?Test\B', (string) Reflection::getParameterType($params[6]));
51+
Assert::same('mixed', (string) Reflection::getParameterType($params[7]));
6152

6253
$method = new ReflectionMethod('AExt', 'methodExt');
6354
$params = $method->getParameters();
6455

65-
Assert::same('A', Reflection::getParameterType($params[0]));
56+
Assert::same('A', (string) Reflection::getParameterType($params[0]));

tests/Utils/Reflection.getPropertyType.81.phpt

+9-20
Original file line numberDiff line numberDiff line change
@@ -37,27 +37,16 @@ class AExt extends A
3737
$class = new ReflectionClass('A');
3838
$props = $class->getProperties();
3939

40-
Assert::same('Undeclared', Reflection::getPropertyType($props[0]));
41-
Assert::same('Test\B', Reflection::getPropertyType($props[1]));
42-
Assert::same('array', Reflection::getPropertyType($props[2]));
43-
Assert::same('A', Reflection::getPropertyType($props[3]));
40+
Assert::same('Undeclared', (string) Reflection::getPropertyType($props[0]));
41+
Assert::same('Test\B', (string) Reflection::getPropertyType($props[1]));
42+
Assert::same('array', (string) Reflection::getPropertyType($props[2]));
43+
Assert::same('A', (string) Reflection::getPropertyType($props[3]));
4444
Assert::null(Reflection::getPropertyType($props[4]));
45-
Assert::same('Test\B', Reflection::getPropertyType($props[5]));
46-
Assert::same('mixed', Reflection::getPropertyType($props[6]));
47-
48-
Assert::exception(function () use ($props) {
49-
Reflection::getPropertyType($props[7]);
50-
}, Nette\InvalidStateException::class, 'The A::$union is not expected to have a union or intersection type.');
51-
52-
Assert::exception(function () use ($props) {
53-
Reflection::getPropertyType($props[8]);
54-
}, Nette\InvalidStateException::class, 'The A::$nullableUnion is not expected to have a union or intersection type.');
55-
56-
Assert::exception(function () use ($props) {
57-
Reflection::getPropertyType($props[9]);
58-
}, Nette\InvalidStateException::class, 'The A::$intersection is not expected to have a union or intersection type.');
59-
45+
Assert::same('?Test\B', (string) Reflection::getPropertyType($props[5]));
46+
Assert::same('mixed', (string) Reflection::getPropertyType($props[6]));
47+
Assert::same('A|array', (string) Reflection::getPropertyType($props[7], false));
48+
Assert::same('A|array|null', (string) Reflection::getPropertyType($props[8], false));
6049
$class = new ReflectionClass('AExt');
6150
$props = $class->getProperties();
6251

63-
Assert::same('A', Reflection::getPropertyType($props[0]));
52+
Assert::same('A', (string) Reflection::getPropertyType($props[0]));

tests/Utils/Reflection.getPropertyType.phpt

+7-16
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,14 @@ class AExt extends A
3535
$class = new ReflectionClass('A');
3636
$props = $class->getProperties();
3737

38-
Assert::same('Undeclared', Reflection::getPropertyType($props[0]));
39-
Assert::same('Test\B', Reflection::getPropertyType($props[1]));
40-
Assert::same('array', Reflection::getPropertyType($props[2]));
41-
Assert::same('A', Reflection::getPropertyType($props[3]));
38+
Assert::same('Undeclared', (string) Reflection::getPropertyType($props[0]));
39+
Assert::same('Test\B', (string) Reflection::getPropertyType($props[1]));
40+
Assert::same('array', (string) Reflection::getPropertyType($props[2]));
41+
Assert::same('A', (string) Reflection::getPropertyType($props[3]));
4242
Assert::null(Reflection::getPropertyType($props[4]));
43-
Assert::same('Test\B', Reflection::getPropertyType($props[5]));
44-
Assert::same('mixed', Reflection::getPropertyType($props[6]));
45-
46-
Assert::exception(function () use ($props) {
47-
Reflection::getPropertyType($props[7]);
48-
}, Nette\InvalidStateException::class, 'The A::$union is not expected to have a union or intersection type.');
49-
50-
Assert::exception(function () use ($props) {
51-
Reflection::getPropertyType($props[8]);
52-
}, Nette\InvalidStateException::class, 'The A::$nullableUnion is not expected to have a union or intersection type.');
53-
43+
Assert::same('?Test\B', (string) Reflection::getPropertyType($props[5]));
44+
Assert::same('mixed', (string) Reflection::getPropertyType($props[6]));
5445
$class = new ReflectionClass('AExt');
5546
$props = $class->getProperties();
5647

57-
Assert::same('A', Reflection::getPropertyType($props[0]));
48+
Assert::same('A', (string) Reflection::getPropertyType($props[0]));

tests/Utils/Reflection.getReturnType.81.phpt

+16-26
Original file line numberDiff line numberDiff line change
@@ -106,48 +106,38 @@ function intersectionType(): AExt&A
106106

107107
Assert::null(Reflection::getReturnType(new \ReflectionMethod(A::class, 'noType')));
108108

109-
Assert::same('Test\B', Reflection::getReturnType(new \ReflectionMethod(A::class, 'classType')));
109+
Assert::same('Test\B', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'classType')));
110110

111-
Assert::same('string', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nativeType')));
111+
Assert::same('string', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nativeType')));
112112

113-
Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(A::class, 'selfType')));
113+
Assert::same('A', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'selfType')));
114114

115-
Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(A::class, 'staticType')));
115+
Assert::same('A', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'staticType')));
116116

117-
Assert::same('Test\B', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableClassType')));
117+
Assert::same('?Test\B', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableClassType')));
118118

119-
Assert::same('string', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableNativeType')));
119+
Assert::same('?string', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableNativeType')));
120120

121-
Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableSelfType')));
121+
Assert::same('?A', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableSelfType')));
122122

123-
Assert::exception(function () {
124-
Reflection::getReturnType(new \ReflectionMethod(A::class, 'unionType'));
125-
}, Nette\InvalidStateException::class, 'The A::unionType() is not expected to have a union or intersection type.');
123+
Assert::same('A|array', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'unionType')));
126124

127-
Assert::exception(function () {
128-
Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableUnionType'));
129-
}, Nette\InvalidStateException::class, 'The A::nullableUnionType() is not expected to have a union or intersection type.');
125+
Assert::same('A|array|null', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableUnionType')));
130126

131-
Assert::exception(function () {
132-
Reflection::getReturnType(new \ReflectionMethod(A::class, 'intersectionType'));
133-
}, Nette\InvalidStateException::class, 'The A::intersectionType() is not expected to have a union or intersection type.');
127+
Assert::same('AExt&A', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'intersectionType')));
134128

135-
Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(AExt::class, 'parentTypeExt')));
129+
Assert::same('A', (string) Reflection::getReturnType(new \ReflectionMethod(AExt::class, 'parentTypeExt')));
136130

137131
Assert::null(Reflection::getReturnType(new \ReflectionFunction('noType')));
138132

139-
Assert::same('Test\B', Reflection::getReturnType(new \ReflectionFunction('classType')));
133+
Assert::same('Test\B', (string) Reflection::getReturnType(new \ReflectionFunction('classType')));
140134

141-
Assert::same('string', Reflection::getReturnType(new \ReflectionFunction('nativeType')));
135+
Assert::same('string', (string) Reflection::getReturnType(new \ReflectionFunction('nativeType')));
142136

143-
Assert::exception(function () {
144-
Reflection::getReturnType(new \ReflectionFunction('unionType'));
145-
}, Nette\InvalidStateException::class, 'The unionType() is not expected to have a union or intersection type.');
137+
Assert::same('A|array', (string) Reflection::getReturnType(new \ReflectionFunction('unionType')));
146138

147-
Assert::exception(function () {
148-
Reflection::getReturnType(new \ReflectionFunction('intersectionType'));
149-
}, Nette\InvalidStateException::class, 'The intersectionType() is not expected to have a union or intersection type.');
139+
Assert::same('AExt&A', (string) Reflection::getReturnType(new \ReflectionFunction('intersectionType')));
150140

151141

152142
// tentative type
153-
Assert::same('int', Reflection::getReturnType(new \ReflectionMethod(\ArrayObject::class, 'count')));
143+
Assert::same('int', (string) Reflection::getReturnType(new \ReflectionMethod(\ArrayObject::class, 'count')));

tests/Utils/Reflection.getReturnType.phpt

+13-19
Original file line numberDiff line numberDiff line change
@@ -95,36 +95,30 @@ function unionType(): array|A
9595

9696
Assert::null(Reflection::getReturnType(new \ReflectionMethod(A::class, 'noType')));
9797

98-
Assert::same('Test\B', Reflection::getReturnType(new \ReflectionMethod(A::class, 'classType')));
98+
Assert::same('Test\B', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'classType')));
9999

100-
Assert::same('string', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nativeType')));
100+
Assert::same('string', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nativeType')));
101101

102-
Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(A::class, 'selfType')));
102+
Assert::same('A', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'selfType')));
103103

104-
Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(A::class, 'staticType')));
104+
Assert::same('A', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'staticType')));
105105

106-
Assert::same('Test\B', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableClassType')));
106+
Assert::same('?Test\B', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableClassType')));
107107

108-
Assert::same('string', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableNativeType')));
108+
Assert::same('?string', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableNativeType')));
109109

110-
Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableSelfType')));
110+
Assert::same('?A', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableSelfType')));
111111

112-
Assert::exception(function () {
113-
Reflection::getReturnType(new \ReflectionMethod(A::class, 'unionType'));
114-
}, Nette\InvalidStateException::class, 'The A::unionType() is not expected to have a union or intersection type.');
112+
Assert::same('A|array', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'unionType')));
115113

116-
Assert::exception(function () {
117-
Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableUnionType'));
118-
}, Nette\InvalidStateException::class, 'The A::nullableUnionType() is not expected to have a union or intersection type.');
114+
Assert::same('A|array|null', (string) Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableUnionType')));
119115

120-
Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(AExt::class, 'parentTypeExt')));
116+
Assert::same('A', (string) Reflection::getReturnType(new \ReflectionMethod(AExt::class, 'parentTypeExt')));
121117

122118
Assert::null(Reflection::getReturnType(new \ReflectionFunction('noType')));
123119

124-
Assert::same('Test\B', Reflection::getReturnType(new \ReflectionFunction('classType')));
120+
Assert::same('Test\B', (string) Reflection::getReturnType(new \ReflectionFunction('classType')));
125121

126-
Assert::same('string', Reflection::getReturnType(new \ReflectionFunction('nativeType')));
122+
Assert::same('string', (string) Reflection::getReturnType(new \ReflectionFunction('nativeType')));
127123

128-
Assert::exception(function () {
129-
Reflection::getReturnType(new \ReflectionFunction('unionType'));
130-
}, Nette\InvalidStateException::class, 'The unionType() is not expected to have a union or intersection type.');
124+
Assert::same('A|array', (string) Reflection::getReturnType(new \ReflectionFunction('unionType')));

0 commit comments

Comments
 (0)