1: | <?php |
2: | |
3: | declare(strict_types=1); |
4: | |
5: | namespace PHPStan\BetterReflection\Reflection; |
6: | |
7: | use LogicException; |
8: | use PhpParser\Node\Identifier; |
9: | use PhpParser\Node\Name; |
10: | use PHPStan\BetterReflection\Reflector\Reflector; |
11: | |
12: | use function array_key_exists; |
13: | use function assert; |
14: | use function sprintf; |
15: | use function strtolower; |
16: | |
17: | |
18: | class ReflectionNamedType extends ReflectionType |
19: | { |
20: | private const BUILT_IN_TYPES = [ |
21: | 'int' => null, |
22: | 'float' => null, |
23: | 'string' => null, |
24: | 'bool' => null, |
25: | 'callable' => null, |
26: | 'self' => null, |
27: | 'parent' => null, |
28: | 'array' => null, |
29: | 'iterable' => null, |
30: | 'object' => null, |
31: | 'void' => null, |
32: | 'mixed' => null, |
33: | 'static' => null, |
34: | 'null' => null, |
35: | 'never' => null, |
36: | 'false' => null, |
37: | 'true' => null, |
38: | ]; |
39: | |
40: | |
41: | private $name; |
42: | |
43: | |
44: | |
45: | private $reflector; |
46: | |
47: | |
48: | |
49: | private $owner; |
50: | |
51: | |
52: | |
53: | private $type; |
54: | |
55: | |
56: | |
57: | public function __construct(Reflector $reflector, $owner, $type) |
58: | { |
59: | $this->reflector = $reflector; |
60: | $this->owner = $owner; |
61: | $this->type = $type; |
62: | $name = $type->toString(); |
63: | assert($name !== ''); |
64: | $this->name = $name; |
65: | } |
66: | |
67: | |
68: | |
69: | |
70: | public function withOwner($owner) |
71: | { |
72: | $clone = clone $this; |
73: | $clone->owner = $owner; |
74: | |
75: | return $clone; |
76: | } |
77: | |
78: | |
79: | public function getName(): string |
80: | { |
81: | return $this->name; |
82: | } |
83: | |
84: | |
85: | |
86: | |
87: | |
88: | |
89: | public function isBuiltin(): bool |
90: | { |
91: | return array_key_exists(strtolower($this->name), self::BUILT_IN_TYPES); |
92: | } |
93: | |
94: | public function getClass(): ReflectionClass |
95: | { |
96: | if (! $this->isBuiltin()) { |
97: | return $this->reflector->reflectClass($this->name); |
98: | } |
99: | |
100: | if ( |
101: | $this->owner instanceof ReflectionEnum |
102: | || $this->owner instanceof ReflectionFunction |
103: | || ($this->owner instanceof ReflectionParameter && $this->owner->getDeclaringFunction() instanceof ReflectionFunction) |
104: | ) { |
105: | throw new LogicException(sprintf('The type %s cannot be resolved to class', $this->name)); |
106: | } |
107: | |
108: | $lowercaseName = strtolower($this->name); |
109: | |
110: | if ($lowercaseName === 'self') { |
111: | $class = $this->owner->getImplementingClass(); |
112: | assert($class instanceof ReflectionClass); |
113: | |
114: | return $class; |
115: | } |
116: | |
117: | if ($lowercaseName === 'parent') { |
118: | $class = $this->owner->getDeclaringClass(); |
119: | assert($class instanceof ReflectionClass); |
120: | $parentClass = $class->getParentClass(); |
121: | assert($parentClass instanceof ReflectionClass); |
122: | |
123: | return $parentClass; |
124: | } |
125: | |
126: | if ( |
127: | $this->owner instanceof ReflectionMethod |
128: | && $lowercaseName === 'static' |
129: | ) { |
130: | return $this->owner->getCurrentClass(); |
131: | } |
132: | |
133: | throw new LogicException(sprintf('The type %s cannot be resolved to class', $this->name)); |
134: | } |
135: | |
136: | public function allowsNull(): bool |
137: | { |
138: | switch (strtolower($this->name)) { |
139: | case 'mixed': |
140: | return true; |
141: | case 'null': |
142: | return true; |
143: | default: |
144: | return false; |
145: | } |
146: | } |
147: | |
148: | public function isIdentifier(): bool |
149: | { |
150: | return $this->type instanceof Identifier; |
151: | } |
152: | |
153: | |
154: | public function __toString(): string |
155: | { |
156: | return $this->getName(); |
157: | } |
158: | } |
159: | |