1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
<?php declare(strict_types=1);
/*
* This file is part of sebastian/type.
*
* (c) Sebastian Bergmann <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\Type;
use function assert;
use function sprintf;
use ReflectionMethod;
use ReflectionNamedType;
use ReflectionType;
use ReflectionUnionType;
final class ReflectionMapper
{
public function fromMethodReturnType(ReflectionMethod $method): Type
{
if (!$this->reflectionMethodHasReturnType($method)) {
return new UnknownType;
}
$returnType = $this->reflectionMethodGetReturnType($method);
assert($returnType instanceof ReflectionNamedType || $returnType instanceof ReflectionUnionType);
if ($returnType instanceof ReflectionNamedType) {
if ($returnType->getName() === 'self') {
return ObjectType::fromName(
$method->getDeclaringClass()->getName(),
$returnType->allowsNull()
);
}
if ($returnType->getName() === 'static') {
return new StaticType(
TypeName::fromReflection($method->getDeclaringClass()),
$returnType->allowsNull()
);
}
if ($returnType->getName() === 'mixed') {
return new MixedType;
}
if ($returnType->getName() === 'parent') {
$parentClass = $method->getDeclaringClass()->getParentClass();
// @codeCoverageIgnoreStart
if ($parentClass === false) {
throw new RuntimeException(
sprintf(
'%s::%s() has a "parent" return type declaration but %s does not have a parent class',
$method->getDeclaringClass()->getName(),
$method->getName(),
$method->getDeclaringClass()->getName()
)
);
}
// @codeCoverageIgnoreEnd
return ObjectType::fromName(
$parentClass->getName(),
$returnType->allowsNull()
);
}
return Type::fromName(
$returnType->getName(),
$returnType->allowsNull()
);
}
assert($returnType instanceof ReflectionUnionType);
$types = [];
foreach ($returnType->getTypes() as $type) {
assert($type instanceof ReflectionNamedType);
if ($type->getName() === 'self') {
$types[] = ObjectType::fromName(
$method->getDeclaringClass()->getName(),
false
);
} else {
$types[] = Type::fromName($type->getName(), false);
}
}
return new UnionType(...$types);
}
private function reflectionMethodHasReturnType(ReflectionMethod $method): bool
{
if ($method->hasReturnType()) {
return true;
}
if (!method_exists($method, 'hasTentativeReturnType')) {
return false;
}
return $method->hasTentativeReturnType();
}
private function reflectionMethodGetReturnType(ReflectionMethod $method): ?ReflectionType
{
if ($method->hasReturnType()) {
return $method->getReturnType();
}
if (!method_exists($method, 'getTentativeReturnType')) {
return null;
}
return $method->getTentativeReturnType();
}
}
|