1: | <?php |
2: | |
3: | declare(strict_types=1); |
4: | |
5: | namespace PHPStan\BetterReflection\Reflection\Adapter; |
6: | |
7: | use Closure; |
8: | use OutOfBoundsException; |
9: | use ReflectionClass as CoreReflectionClass; |
10: | use ReflectionException as CoreReflectionException; |
11: | use ReflectionExtension as CoreReflectionExtension; |
12: | use ReflectionFunction as CoreReflectionFunction; |
13: | use ReflectionType as CoreReflectionType; |
14: | use ReturnTypeWillChange; |
15: | use PHPStan\BetterReflection\Reflection\Adapter\Exception\NotImplemented; |
16: | use PHPStan\BetterReflection\Reflection\ReflectionAttribute as BetterReflectionAttribute; |
17: | use PHPStan\BetterReflection\Reflection\ReflectionFunction as BetterReflectionFunction; |
18: | use PHPStan\BetterReflection\Reflection\ReflectionParameter as BetterReflectionParameter; |
19: | use PHPStan\BetterReflection\Util\FileHelper; |
20: | use Throwable; |
21: | use ValueError; |
22: | |
23: | use function array_map; |
24: | use function func_get_args; |
25: | use function sprintf; |
26: | |
27: | final class ReflectionFunction extends CoreReflectionFunction |
28: | { |
29: | private BetterReflectionFunction $betterReflectionFunction; |
30: | public function __construct(BetterReflectionFunction $betterReflectionFunction) |
31: | { |
32: | $this->betterReflectionFunction = $betterReflectionFunction; |
33: | unset($this->name); |
34: | } |
35: | |
36: | public function __toString(): string |
37: | { |
38: | return $this->betterReflectionFunction->__toString(); |
39: | } |
40: | |
41: | public function getBetterReflection(): BetterReflectionFunction |
42: | { |
43: | return $this->betterReflectionFunction; |
44: | } |
45: | |
46: | public function inNamespace(): bool |
47: | { |
48: | return $this->betterReflectionFunction->inNamespace(); |
49: | } |
50: | |
51: | public function isClosure(): bool |
52: | { |
53: | return $this->betterReflectionFunction->isClosure(); |
54: | } |
55: | |
56: | public function isDeprecated(): bool |
57: | { |
58: | return $this->betterReflectionFunction->isDeprecated(); |
59: | } |
60: | |
61: | public function isInternal(): bool |
62: | { |
63: | return $this->betterReflectionFunction->isInternal(); |
64: | } |
65: | |
66: | public function isUserDefined(): bool |
67: | { |
68: | return $this->betterReflectionFunction->isUserDefined(); |
69: | } |
70: | |
71: | |
72: | |
73: | |
74: | #[ReturnTypeWillChange] |
75: | public function getClosureThis() |
76: | { |
77: | throw new NotImplemented('Not implemented'); |
78: | } |
79: | |
80: | public function getClosureScopeClass(): ?CoreReflectionClass |
81: | { |
82: | throw new NotImplemented('Not implemented'); |
83: | } |
84: | |
85: | public function getClosureCalledClass(): ?CoreReflectionClass |
86: | { |
87: | throw new NotImplemented('Not implemented'); |
88: | } |
89: | |
90: | |
91: | |
92: | |
93: | #[ReturnTypeWillChange] |
94: | public function getDocComment() |
95: | { |
96: | return $this->betterReflectionFunction->getDocComment() ?? false; |
97: | } |
98: | |
99: | |
100: | |
101: | |
102: | |
103: | #[ReturnTypeWillChange] |
104: | public function getStartLine() |
105: | { |
106: | return $this->betterReflectionFunction->getStartLine(); |
107: | } |
108: | |
109: | |
110: | |
111: | |
112: | |
113: | #[ReturnTypeWillChange] |
114: | public function getEndLine() |
115: | { |
116: | return $this->betterReflectionFunction->getEndLine(); |
117: | } |
118: | |
119: | |
120: | public function getExtension(): ?CoreReflectionExtension |
121: | { |
122: | throw new NotImplemented('Not implemented'); |
123: | } |
124: | |
125: | |
126: | |
127: | |
128: | #[ReturnTypeWillChange] |
129: | public function getExtensionName() |
130: | { |
131: | return $this->betterReflectionFunction->getExtensionName() ?? false; |
132: | } |
133: | |
134: | |
135: | |
136: | |
137: | #[ReturnTypeWillChange] |
138: | public function getFileName() |
139: | { |
140: | $fileName = $this->betterReflectionFunction->getFileName(); |
141: | |
142: | return $fileName !== null ? FileHelper::normalizeSystemPath($fileName) : false; |
143: | } |
144: | |
145: | public function getName(): string |
146: | { |
147: | return $this->betterReflectionFunction->getName(); |
148: | } |
149: | |
150: | public function getNamespaceName(): string |
151: | { |
152: | return $this->betterReflectionFunction->getNamespaceName() ?? ''; |
153: | } |
154: | |
155: | public function getNumberOfParameters(): int |
156: | { |
157: | return $this->betterReflectionFunction->getNumberOfParameters(); |
158: | } |
159: | |
160: | public function getNumberOfRequiredParameters(): int |
161: | { |
162: | return $this->betterReflectionFunction->getNumberOfRequiredParameters(); |
163: | } |
164: | |
165: | |
166: | public function getParameters(): array |
167: | { |
168: | return array_map( |
169: | static fn (BetterReflectionParameter $parameter): ReflectionParameter => new ReflectionParameter($parameter), |
170: | $this->betterReflectionFunction->getParameters(), |
171: | ); |
172: | } |
173: | |
174: | public function hasReturnType(): bool |
175: | { |
176: | return $this->betterReflectionFunction->hasReturnType(); |
177: | } |
178: | |
179: | |
180: | public function getReturnType(): ?CoreReflectionType |
181: | { |
182: | return ReflectionType::fromTypeOrNull($this->betterReflectionFunction->getReturnType()); |
183: | } |
184: | |
185: | public function getShortName(): string |
186: | { |
187: | return $this->betterReflectionFunction->getShortName(); |
188: | } |
189: | |
190: | |
191: | public function getStaticVariables(): array |
192: | { |
193: | throw new NotImplemented('Not implemented'); |
194: | } |
195: | |
196: | public function returnsReference(): bool |
197: | { |
198: | return $this->betterReflectionFunction->returnsReference(); |
199: | } |
200: | |
201: | public function isGenerator(): bool |
202: | { |
203: | return $this->betterReflectionFunction->isGenerator(); |
204: | } |
205: | |
206: | public function isVariadic(): bool |
207: | { |
208: | return $this->betterReflectionFunction->isVariadic(); |
209: | } |
210: | |
211: | public function isDisabled(): bool |
212: | { |
213: | return $this->betterReflectionFunction->isDisabled(); |
214: | } |
215: | |
216: | |
217: | |
218: | |
219: | |
220: | |
221: | |
222: | |
223: | |
224: | #[ReturnTypeWillChange] |
225: | public function invoke($arg = null, ...$args) |
226: | { |
227: | try { |
228: | return $this->betterReflectionFunction->invoke(...func_get_args()); |
229: | } catch (Throwable $e) { |
230: | throw new CoreReflectionException($e->getMessage(), 0, $e); |
231: | } |
232: | } |
233: | |
234: | |
235: | |
236: | |
237: | #[ReturnTypeWillChange] |
238: | public function invokeArgs(array $args) |
239: | { |
240: | try { |
241: | return $this->betterReflectionFunction->invokeArgs($args); |
242: | } catch (Throwable $e) { |
243: | throw new CoreReflectionException($e->getMessage(), 0, $e); |
244: | } |
245: | } |
246: | |
247: | public function getClosure(): Closure |
248: | { |
249: | return $this->betterReflectionFunction->getClosure(); |
250: | } |
251: | |
252: | |
253: | |
254: | |
255: | |
256: | |
257: | public function getClosureUsedVariables(): array |
258: | { |
259: | throw new Exception\NotImplemented('Not implemented'); |
260: | } |
261: | |
262: | public function hasTentativeReturnType(): bool |
263: | { |
264: | return $this->betterReflectionFunction->hasTentativeReturnType(); |
265: | } |
266: | |
267: | |
268: | public function getTentativeReturnType(): ?CoreReflectionType |
269: | { |
270: | return ReflectionType::fromTypeOrNull($this->betterReflectionFunction->getTentativeReturnType()); |
271: | } |
272: | |
273: | public function isStatic(): bool |
274: | { |
275: | return $this->betterReflectionFunction->isStatic(); |
276: | } |
277: | |
278: | |
279: | |
280: | |
281: | |
282: | |
283: | public function getAttributes(?string $name = null, int $flags = 0): array |
284: | { |
285: | if ($flags !== 0 && $flags !== ReflectionAttribute::IS_INSTANCEOF) { |
286: | throw new ValueError('Argument #2 ($flags) must be a valid attribute filter flag'); |
287: | } |
288: | |
289: | if ($name !== null && $flags !== 0) { |
290: | $attributes = $this->betterReflectionFunction->getAttributesByInstance($name); |
291: | } elseif ($name !== null) { |
292: | $attributes = $this->betterReflectionFunction->getAttributesByName($name); |
293: | } else { |
294: | $attributes = $this->betterReflectionFunction->getAttributes(); |
295: | } |
296: | |
297: | return array_map(static fn (BetterReflectionAttribute $betterReflectionAttribute) => ReflectionAttributeFactory::create($betterReflectionAttribute), $attributes); |
298: | } |
299: | |
300: | |
301: | |
302: | |
303: | public function __get(string $name) |
304: | { |
305: | if ($name === 'name') { |
306: | return $this->betterReflectionFunction->getName(); |
307: | } |
308: | |
309: | throw new OutOfBoundsException(sprintf('Property %s::$%s does not exist.', self::class, $name)); |
310: | } |
311: | |
312: | public function isAnonymous(): bool |
313: | { |
314: | return $this->betterReflectionFunction->isClosure(); |
315: | } |
316: | } |
317: | |