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