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