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: | public function __construct(Reflector $reflector, $owner, $type) |
54: | { |
55: | $this->reflector = $reflector; |
56: | $this->owner = $owner; |
57: | $name = $type->toString(); |
58: | assert($name !== ''); |
59: | $this->name = $name; |
60: | } |
61: | |
62: | |
63: | |
64: | |
65: | public function withOwner($owner) |
66: | { |
67: | $clone = clone $this; |
68: | $clone->owner = $owner; |
69: | |
70: | return $clone; |
71: | } |
72: | |
73: | |
74: | public function getName(): string |
75: | { |
76: | return $this->name; |
77: | } |
78: | |
79: | |
80: | |
81: | |
82: | |
83: | |
84: | public function isBuiltin(): bool |
85: | { |
86: | return array_key_exists(strtolower($this->name), self::BUILT_IN_TYPES); |
87: | } |
88: | |
89: | public function getClass(): ReflectionClass |
90: | { |
91: | if (! $this->isBuiltin()) { |
92: | return $this->reflector->reflectClass($this->name); |
93: | } |
94: | |
95: | if ( |
96: | $this->owner instanceof ReflectionEnum |
97: | || $this->owner instanceof ReflectionFunction |
98: | || ($this->owner instanceof ReflectionParameter && $this->owner->getDeclaringFunction() instanceof ReflectionFunction) |
99: | ) { |
100: | throw new LogicException(sprintf('The type %s cannot be resolved to class', $this->name)); |
101: | } |
102: | |
103: | $lowercaseName = strtolower($this->name); |
104: | |
105: | if ($lowercaseName === 'self') { |
106: | $class = $this->owner->getImplementingClass(); |
107: | assert($class instanceof ReflectionClass); |
108: | |
109: | return $class; |
110: | } |
111: | |
112: | if ($lowercaseName === 'parent') { |
113: | $class = $this->owner->getDeclaringClass(); |
114: | assert($class instanceof ReflectionClass); |
115: | $parentClass = $class->getParentClass(); |
116: | assert($parentClass instanceof ReflectionClass); |
117: | |
118: | return $parentClass; |
119: | } |
120: | |
121: | if ( |
122: | $this->owner instanceof ReflectionMethod |
123: | && $lowercaseName === 'static' |
124: | ) { |
125: | return $this->owner->getCurrentClass(); |
126: | } |
127: | |
128: | throw new LogicException(sprintf('The type %s cannot be resolved to class', $this->name)); |
129: | } |
130: | |
131: | public function allowsNull(): bool |
132: | { |
133: | switch (strtolower($this->name)) { |
134: | case 'mixed': |
135: | return true; |
136: | case 'null': |
137: | return true; |
138: | default: |
139: | return false; |
140: | } |
141: | } |
142: | |
143: | |
144: | public function __toString(): string |
145: | { |
146: | return $this->getName(); |
147: | } |
148: | } |
149: | |