1: | <?php |
2: | |
3: | declare(strict_types=1); |
4: | |
5: | namespace PHPStan\BetterReflection\Reflection\Adapter; |
6: | |
7: | use OutOfBoundsException; |
8: | use ReflectionClass as CoreReflectionClass; |
9: | use ReflectionException as CoreReflectionException; |
10: | use ReflectionExtension as CoreReflectionExtension; |
11: | use ReflectionObject as CoreReflectionObject; |
12: | use ReturnTypeWillChange; |
13: | use PHPStan\BetterReflection\Reflection\ReflectionAttribute as BetterReflectionAttribute; |
14: | use PHPStan\BetterReflection\Reflection\ReflectionClass as BetterReflectionClass; |
15: | use PHPStan\BetterReflection\Reflection\ReflectionClassConstant as BetterReflectionClassConstant; |
16: | use PHPStan\BetterReflection\Reflection\ReflectionMethod as BetterReflectionMethod; |
17: | use PHPStan\BetterReflection\Reflection\ReflectionObject as BetterReflectionObject; |
18: | use PHPStan\BetterReflection\Reflection\ReflectionProperty as BetterReflectionProperty; |
19: | use PHPStan\BetterReflection\Util\FileHelper; |
20: | use ValueError; |
21: | |
22: | use function array_combine; |
23: | use function array_map; |
24: | use function array_values; |
25: | use function func_num_args; |
26: | use function sprintf; |
27: | use function strtolower; |
28: | |
29: | |
30: | final class ReflectionObject extends CoreReflectionObject |
31: | { |
32: | private BetterReflectionObject $betterReflectionObject; |
33: | public function __construct(BetterReflectionObject $betterReflectionObject) |
34: | { |
35: | $this->betterReflectionObject = $betterReflectionObject; |
36: | unset($this->name); |
37: | } |
38: | |
39: | |
40: | public function __toString(): string |
41: | { |
42: | return $this->betterReflectionObject->__toString(); |
43: | } |
44: | |
45: | public function getName(): string |
46: | { |
47: | return $this->betterReflectionObject->getName(); |
48: | } |
49: | |
50: | public function getBetterReflection(): BetterReflectionObject |
51: | { |
52: | return $this->betterReflectionObject; |
53: | } |
54: | |
55: | public function isInternal(): bool |
56: | { |
57: | return $this->betterReflectionObject->isInternal(); |
58: | } |
59: | |
60: | public function isUserDefined(): bool |
61: | { |
62: | return $this->betterReflectionObject->isUserDefined(); |
63: | } |
64: | |
65: | public function isInstantiable(): bool |
66: | { |
67: | return $this->betterReflectionObject->isInstantiable(); |
68: | } |
69: | |
70: | public function isCloneable(): bool |
71: | { |
72: | return $this->betterReflectionObject->isCloneable(); |
73: | } |
74: | |
75: | |
76: | |
77: | |
78: | |
79: | #[ReturnTypeWillChange] |
80: | public function getFileName() |
81: | { |
82: | $fileName = $this->betterReflectionObject->getFileName(); |
83: | |
84: | return $fileName !== null ? FileHelper::normalizeSystemPath($fileName) : false; |
85: | } |
86: | |
87: | |
88: | |
89: | |
90: | |
91: | #[ReturnTypeWillChange] |
92: | public function getStartLine() |
93: | { |
94: | return $this->betterReflectionObject->getStartLine(); |
95: | } |
96: | |
97: | |
98: | |
99: | |
100: | |
101: | #[ReturnTypeWillChange] |
102: | public function getEndLine() |
103: | { |
104: | return $this->betterReflectionObject->getEndLine(); |
105: | } |
106: | |
107: | |
108: | |
109: | |
110: | #[ReturnTypeWillChange] |
111: | public function getDocComment() |
112: | { |
113: | return $this->betterReflectionObject->getDocComment() ?? false; |
114: | } |
115: | |
116: | public function getConstructor(): ?\PHPStan\BetterReflection\Reflection\Adapter\ReflectionMethod |
117: | { |
118: | $constructor = $this->betterReflectionObject->getConstructor(); |
119: | |
120: | if ($constructor === null) { |
121: | return null; |
122: | } |
123: | |
124: | return new ReflectionMethod($constructor); |
125: | } |
126: | |
127: | |
128: | |
129: | |
130: | public function hasMethod($name): bool |
131: | { |
132: | if ($name === '') { |
133: | return false; |
134: | } |
135: | |
136: | return $this->betterReflectionObject->hasMethod($this->getMethodRealName($name)); |
137: | } |
138: | |
139: | |
140: | |
141: | |
142: | public function getMethod($name): ReflectionMethod |
143: | { |
144: | $method = $name !== '' ? $this->betterReflectionObject->getMethod($this->getMethodRealName($name)) : null; |
145: | |
146: | if ($method === null) { |
147: | throw new CoreReflectionException(sprintf('Method %s::%s() does not exist', $this->betterReflectionObject->getName(), $name)); |
148: | } |
149: | |
150: | return new ReflectionMethod($method); |
151: | } |
152: | |
153: | |
154: | |
155: | |
156: | |
157: | |
158: | private function getMethodRealName(string $name): string |
159: | { |
160: | $realMethodNames = array_map(static fn (BetterReflectionMethod $method): string => $method->getName(), $this->betterReflectionObject->getMethods()); |
161: | |
162: | $methodNames = array_combine(array_map(static fn (string $methodName): string => strtolower($methodName), $realMethodNames), $realMethodNames); |
163: | |
164: | $lowercasedName = strtolower($name); |
165: | |
166: | return $methodNames[$lowercasedName] ?? $name; |
167: | } |
168: | |
169: | |
170: | |
171: | |
172: | |
173: | public function getMethods($filter = null): array |
174: | { |
175: | return array_values(array_map( |
176: | static fn (BetterReflectionMethod $method): ReflectionMethod => new ReflectionMethod($method), |
177: | $this->betterReflectionObject->getMethods($filter ?? 0), |
178: | )); |
179: | } |
180: | |
181: | |
182: | |
183: | |
184: | public function hasProperty($name): bool |
185: | { |
186: | if ($name === '') { |
187: | return false; |
188: | } |
189: | |
190: | return $this->betterReflectionObject->hasProperty($name); |
191: | } |
192: | |
193: | |
194: | |
195: | |
196: | |
197: | public function getProperty($name): \ReflectionProperty |
198: | { |
199: | $property = $name !== '' ? $this->betterReflectionObject->getProperty($name) : null; |
200: | |
201: | if ($property === null) { |
202: | throw new CoreReflectionException(sprintf('Property %s::$%s does not exist', $this->betterReflectionObject->getName(), $name)); |
203: | } |
204: | |
205: | return new ReflectionProperty($property); |
206: | } |
207: | |
208: | |
209: | |
210: | |
211: | |
212: | public function getProperties($filter = null): array |
213: | { |
214: | return array_values(array_map( |
215: | static fn (BetterReflectionProperty $property): ReflectionProperty => new ReflectionProperty($property), |
216: | $this->betterReflectionObject->getProperties($filter ?? 0), |
217: | )); |
218: | } |
219: | |
220: | |
221: | |
222: | |
223: | public function hasConstant($name): bool |
224: | { |
225: | if ($name === '') { |
226: | return false; |
227: | } |
228: | |
229: | return $this->betterReflectionObject->hasConstant($name); |
230: | } |
231: | |
232: | |
233: | |
234: | |
235: | |
236: | |
237: | public function getConstants(?int $filter = null): array |
238: | { |
239: | return array_map( |
240: | static fn (BetterReflectionClassConstant $betterConstant) => $betterConstant->getValue(), |
241: | $this->betterReflectionObject->getConstants($filter ?? 0), |
242: | ); |
243: | } |
244: | |
245: | |
246: | |
247: | |
248: | #[ReturnTypeWillChange] |
249: | public function getConstant($name) |
250: | { |
251: | if ($name === '') { |
252: | return false; |
253: | } |
254: | |
255: | $betterReflectionConstant = $this->betterReflectionObject->getConstant($name); |
256: | if ($betterReflectionConstant === null) { |
257: | return false; |
258: | } |
259: | |
260: | return $betterReflectionConstant->getValue(); |
261: | } |
262: | |
263: | |
264: | |
265: | |
266: | |
267: | #[ReturnTypeWillChange] |
268: | public function getReflectionConstant($name) |
269: | { |
270: | if ($name === '') { |
271: | return false; |
272: | } |
273: | |
274: | $betterReflectionConstant = $this->betterReflectionObject->getConstant($name); |
275: | |
276: | if ($betterReflectionConstant === null) { |
277: | return false; |
278: | } |
279: | |
280: | return new ReflectionClassConstant($betterReflectionConstant); |
281: | } |
282: | |
283: | |
284: | |
285: | |
286: | |
287: | |
288: | public function getReflectionConstants(?int $filter = null): array |
289: | { |
290: | return array_values(array_map( |
291: | static fn (BetterReflectionClassConstant $betterConstant): ReflectionClassConstant => new ReflectionClassConstant($betterConstant), |
292: | $this->betterReflectionObject->getConstants($filter ?? 0), |
293: | )); |
294: | } |
295: | |
296: | |
297: | public function getInterfaces(): array |
298: | { |
299: | return array_map( |
300: | static fn (BetterReflectionClass $interface): ReflectionClass => new ReflectionClass($interface), |
301: | $this->betterReflectionObject->getInterfaces(), |
302: | ); |
303: | } |
304: | |
305: | |
306: | public function getInterfaceNames(): array |
307: | { |
308: | return $this->betterReflectionObject->getInterfaceNames(); |
309: | } |
310: | |
311: | public function isInterface(): bool |
312: | { |
313: | return $this->betterReflectionObject->isInterface(); |
314: | } |
315: | |
316: | |
317: | public function getTraits(): array |
318: | { |
319: | $traits = $this->betterReflectionObject->getTraits(); |
320: | |
321: | |
322: | $traitNames = array_map(static fn (BetterReflectionClass $trait): string => $trait->getName(), $traits); |
323: | |
324: | return array_combine( |
325: | $traitNames, |
326: | array_map(static fn (BetterReflectionClass $trait): ReflectionClass => new ReflectionClass($trait), $traits), |
327: | ); |
328: | } |
329: | |
330: | |
331: | public function getTraitNames(): array |
332: | { |
333: | return $this->betterReflectionObject->getTraitNames(); |
334: | } |
335: | |
336: | |
337: | public function getTraitAliases(): array |
338: | { |
339: | return $this->betterReflectionObject->getTraitAliases(); |
340: | } |
341: | |
342: | public function isTrait(): bool |
343: | { |
344: | return $this->betterReflectionObject->isTrait(); |
345: | } |
346: | |
347: | public function isAbstract(): bool |
348: | { |
349: | return $this->betterReflectionObject->isAbstract(); |
350: | } |
351: | |
352: | public function isFinal(): bool |
353: | { |
354: | return $this->betterReflectionObject->isFinal(); |
355: | } |
356: | |
357: | public function isReadOnly(): bool |
358: | { |
359: | return $this->betterReflectionObject->isReadOnly(); |
360: | } |
361: | |
362: | public function getModifiers(): int |
363: | { |
364: | return $this->betterReflectionObject->getModifiers(); |
365: | } |
366: | |
367: | |
368: | |
369: | |
370: | public function isInstance($object): bool |
371: | { |
372: | return $this->betterReflectionObject->isInstance($object); |
373: | } |
374: | |
375: | |
376: | |
377: | |
378: | |
379: | |
380: | |
381: | #[ReturnTypeWillChange] |
382: | public function newInstance($arg = null, ...$args) |
383: | { |
384: | throw Exception\NotImplementedBecauseItTriggersAutoloading::create(); |
385: | } |
386: | |
387: | |
388: | |
389: | |
390: | #[ReturnTypeWillChange] |
391: | public function newInstanceWithoutConstructor() |
392: | { |
393: | throw Exception\NotImplementedBecauseItTriggersAutoloading::create(); |
394: | } |
395: | |
396: | |
397: | |
398: | |
399: | #[ReturnTypeWillChange] |
400: | public function newInstanceArgs(?array $args = null) |
401: | { |
402: | throw Exception\NotImplementedBecauseItTriggersAutoloading::create(); |
403: | } |
404: | |
405: | |
406: | |
407: | |
408: | |
409: | |
410: | public function newLazyGhost(callable $initializer, int $options = 0): object |
411: | { |
412: | throw Exception\NotImplementedBecauseItTriggersAutoloading::create(); |
413: | } |
414: | |
415: | |
416: | |
417: | |
418: | |
419: | |
420: | public function newLazyProxy(callable $factory, int $options = 0): object |
421: | { |
422: | throw Exception\NotImplementedBecauseItTriggersAutoloading::create(); |
423: | } |
424: | |
425: | |
426: | public function markLazyObjectAsInitialized(object $object): object |
427: | { |
428: | throw Exception\NotImplementedBecauseItTriggersAutoloading::create(); |
429: | } |
430: | |
431: | public function getLazyInitializer(object $object): ?callable |
432: | { |
433: | throw Exception\NotImplementedBecauseItTriggersAutoloading::create(); |
434: | } |
435: | |
436: | |
437: | public function initializeLazyObject(object $object): object |
438: | { |
439: | throw Exception\NotImplementedBecauseItTriggersAutoloading::create(); |
440: | } |
441: | |
442: | |
443: | public function isUninitializedLazyObject(object $object): bool |
444: | { |
445: | throw Exception\NotImplementedBecauseItTriggersAutoloading::create(); |
446: | } |
447: | |
448: | |
449: | public function resetAsLazyGhost(object $object, callable $initializer, int $options = 0): void |
450: | { |
451: | throw Exception\NotImplementedBecauseItTriggersAutoloading::create(); |
452: | } |
453: | |
454: | |
455: | public function resetAsLazyProxy(object $object, callable $factory, int $options = 0): void |
456: | { |
457: | throw Exception\NotImplementedBecauseItTriggersAutoloading::create(); |
458: | } |
459: | |
460: | |
461: | |
462: | |
463: | |
464: | |
465: | #[ReturnTypeWillChange] |
466: | public function getParentClass() |
467: | { |
468: | $parentClass = $this->betterReflectionObject->getParentClass(); |
469: | |
470: | if ($parentClass === null) { |
471: | return false; |
472: | } |
473: | |
474: | return new ReflectionClass($parentClass); |
475: | } |
476: | |
477: | |
478: | |
479: | |
480: | public function isSubclassOf($class): bool |
481: | { |
482: | $realParentClassNames = $this->betterReflectionObject->getParentClassNames(); |
483: | |
484: | $parentClassNames = array_combine(array_map(static fn (string $parentClassName): string => strtolower($parentClassName), $realParentClassNames), $realParentClassNames); |
485: | |
486: | $className = $class instanceof CoreReflectionClass ? $class->getName() : $class; |
487: | $lowercasedClassName = strtolower($className); |
488: | |
489: | $realParentClassName = $parentClassNames[$lowercasedClassName] ?? $className; |
490: | |
491: | return $this->betterReflectionObject->isSubclassOf($realParentClassName); |
492: | } |
493: | |
494: | |
495: | |
496: | |
497: | |
498: | |
499: | public function getStaticProperties(): array |
500: | { |
501: | return $this->betterReflectionObject->getStaticProperties(); |
502: | } |
503: | |
504: | |
505: | |
506: | |
507: | #[ReturnTypeWillChange] |
508: | public function getStaticPropertyValue($name, $default = null) |
509: | { |
510: | $betterReflectionProperty = $name !== '' ? $this->betterReflectionObject->getProperty($name) : null; |
511: | |
512: | if ($betterReflectionProperty === null) { |
513: | if (func_num_args() === 2) { |
514: | return $default; |
515: | } |
516: | |
517: | throw new CoreReflectionException(sprintf('Property %s::$%s does not exist', $this->betterReflectionObject->getName(), $name)); |
518: | } |
519: | |
520: | $property = new ReflectionProperty($betterReflectionProperty); |
521: | |
522: | if (! $property->isStatic()) { |
523: | throw new CoreReflectionException(sprintf('Property %s::$%s does not exist', $this->betterReflectionObject->getName(), $name)); |
524: | } |
525: | |
526: | return $property->getValue(); |
527: | } |
528: | |
529: | |
530: | |
531: | |
532: | public function setStaticPropertyValue($name, $value): void |
533: | { |
534: | $betterReflectionProperty = $name !== '' ? $this->betterReflectionObject->getProperty($name) : null; |
535: | |
536: | if ($betterReflectionProperty === null) { |
537: | throw new CoreReflectionException(sprintf('Class %s does not have a property named %s', $this->betterReflectionObject->getName(), $name)); |
538: | } |
539: | |
540: | $property = new ReflectionProperty($betterReflectionProperty); |
541: | |
542: | if (! $property->isStatic()) { |
543: | throw new CoreReflectionException(sprintf('Class %s does not have a property named %s', $this->betterReflectionObject->getName(), $name)); |
544: | } |
545: | |
546: | $property->setValue($value); |
547: | } |
548: | |
549: | |
550: | public function getDefaultProperties(): array |
551: | { |
552: | return $this->betterReflectionObject->getDefaultProperties(); |
553: | } |
554: | |
555: | public function isIterateable(): bool |
556: | { |
557: | return $this->betterReflectionObject->isIterateable(); |
558: | } |
559: | |
560: | public function isIterable(): bool |
561: | { |
562: | return $this->isIterateable(); |
563: | } |
564: | |
565: | |
566: | |
567: | |
568: | public function implementsInterface($interface): bool |
569: | { |
570: | $realInterfaceNames = $this->betterReflectionObject->getInterfaceNames(); |
571: | |
572: | $interfaceNames = array_combine(array_map(static fn (string $interfaceName): string => strtolower($interfaceName), $realInterfaceNames), $realInterfaceNames); |
573: | |
574: | $interfaceName = $interface instanceof CoreReflectionClass ? $interface->getName() : $interface; |
575: | $lowercasedInterfaceName = strtolower($interfaceName); |
576: | |
577: | $realInterfaceName = $interfaceNames[$lowercasedInterfaceName] ?? $interfaceName; |
578: | |
579: | return $this->betterReflectionObject->implementsInterface($realInterfaceName); |
580: | } |
581: | |
582: | public function getExtension(): ?CoreReflectionExtension |
583: | { |
584: | throw new Exception\NotImplemented('Not implemented'); |
585: | } |
586: | |
587: | |
588: | |
589: | |
590: | #[ReturnTypeWillChange] |
591: | public function getExtensionName() |
592: | { |
593: | return $this->betterReflectionObject->getExtensionName() ?? false; |
594: | } |
595: | |
596: | public function inNamespace(): bool |
597: | { |
598: | return $this->betterReflectionObject->inNamespace(); |
599: | } |
600: | |
601: | public function getNamespaceName(): string |
602: | { |
603: | return $this->betterReflectionObject->getNamespaceName() ?? ''; |
604: | } |
605: | |
606: | public function getShortName(): string |
607: | { |
608: | return $this->betterReflectionObject->getShortName(); |
609: | } |
610: | |
611: | public function isAnonymous(): bool |
612: | { |
613: | return $this->betterReflectionObject->isAnonymous(); |
614: | } |
615: | |
616: | |
617: | |
618: | |
619: | |
620: | |
621: | public function getAttributes(?string $name = null, int $flags = 0): array |
622: | { |
623: | if ($flags !== 0 && $flags !== ReflectionAttribute::IS_INSTANCEOF) { |
624: | throw new ValueError('Argument #2 ($flags) must be a valid attribute filter flag'); |
625: | } |
626: | |
627: | if ($name !== null && $flags !== 0) { |
628: | $attributes = $this->betterReflectionObject->getAttributesByInstance($name); |
629: | } elseif ($name !== null) { |
630: | $attributes = $this->betterReflectionObject->getAttributesByName($name); |
631: | } else { |
632: | $attributes = $this->betterReflectionObject->getAttributes(); |
633: | } |
634: | |
635: | return array_map(static fn (BetterReflectionAttribute $betterReflectionAttribute) => ReflectionAttributeFactory::create($betterReflectionAttribute), $attributes); |
636: | } |
637: | |
638: | public function isEnum(): bool |
639: | { |
640: | return $this->betterReflectionObject->isEnum(); |
641: | } |
642: | |
643: | |
644: | |
645: | |
646: | public function __get(string $name) |
647: | { |
648: | if ($name === 'name') { |
649: | return $this->betterReflectionObject->getName(); |
650: | } |
651: | |
652: | throw new OutOfBoundsException(sprintf('Property %s::$%s does not exist.', self::class, $name)); |
653: | } |
654: | } |
655: | |