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