1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace PHPStan\BetterReflection\Reflection\Adapter;
6:
7: use OutOfBoundsException;
8: use PhpParser\Node\Expr;
9: use ReflectionEnumBackedCase as CoreReflectionEnumBackedCase;
10: use PHPStan\BetterReflection\Reflection\ReflectionAttribute as BetterReflectionAttribute;
11: use PHPStan\BetterReflection\Reflection\ReflectionEnumCase as BetterReflectionEnumCase;
12: use UnitEnum;
13: use ValueError;
14:
15: use function array_map;
16: use function sprintf;
17:
18: /**
19: * @psalm-suppress PropertyNotSetInConstructor
20: * @psalm-immutable
21: */
22: final class ReflectionEnumBackedCase extends CoreReflectionEnumBackedCase
23: {
24: public function __construct(private BetterReflectionEnumCase $betterReflectionEnumCase)
25: {
26: unset($this->name);
27: unset($this->class);
28: }
29:
30: /**
31: * Get the name of the reflection (e.g. if this is a ReflectionClass this
32: * will be the class name).
33: */
34: public function getName(): string
35: {
36: return $this->betterReflectionEnumCase->getName();
37: }
38:
39: public function getBetterReflection(): BetterReflectionEnumCase
40: {
41: return $this->betterReflectionEnumCase;
42: }
43:
44: public function hasType(): bool
45: {
46: return false;
47: }
48:
49: public function getType(): ?ReflectionType
50: {
51: return null;
52: }
53:
54: /** @return never */
55: public function getValue(): UnitEnum
56: {
57: throw Exception\NotImplementedBecauseItTriggersAutoloading::create();
58: }
59:
60: public function isPublic(): bool
61: {
62: return true;
63: }
64:
65: public function isPrivate(): bool
66: {
67: return false;
68: }
69:
70: public function isProtected(): bool
71: {
72: return false;
73: }
74:
75: public function getModifiers(): int
76: {
77: return self::IS_PUBLIC;
78: }
79:
80: public function getDeclaringClass(): ReflectionClass
81: {
82: return new ReflectionClass($this->betterReflectionEnumCase->getDeclaringClass());
83: }
84:
85: public function getDocComment(): string|false
86: {
87: return $this->betterReflectionEnumCase->getDocComment() ?? false;
88: }
89:
90: /** @return non-empty-string */
91: public function __toString(): string
92: {
93: return $this->betterReflectionEnumCase->__toString();
94: }
95:
96: /**
97: * @param class-string|null $name
98: *
99: * @return list<ReflectionAttribute|FakeReflectionAttribute>
100: */
101: public function getAttributes(string|null $name = null, int $flags = 0): array
102: {
103: if ($flags !== 0 && $flags !== ReflectionAttribute::IS_INSTANCEOF) {
104: throw new ValueError('Argument #2 ($flags) must be a valid attribute filter flag');
105: }
106:
107: if ($name !== null && $flags !== 0) {
108: $attributes = $this->betterReflectionEnumCase->getAttributesByInstance($name);
109: } elseif ($name !== null) {
110: $attributes = $this->betterReflectionEnumCase->getAttributesByName($name);
111: } else {
112: $attributes = $this->betterReflectionEnumCase->getAttributes();
113: }
114:
115: /** @psalm-suppress ImpureFunctionCall */
116: return array_map(static fn (BetterReflectionAttribute $betterReflectionAttribute): ReflectionAttribute|FakeReflectionAttribute => ReflectionAttributeFactory::create($betterReflectionAttribute), $attributes);
117: }
118:
119: public function isFinal(): bool
120: {
121: return true;
122: }
123:
124: public function isEnumCase(): bool
125: {
126: return true;
127: }
128:
129: public function getEnum(): ReflectionEnum
130: {
131: return new ReflectionEnum($this->betterReflectionEnumCase->getDeclaringEnum());
132: }
133:
134: public function getBackingValue(): int|string
135: {
136: return $this->betterReflectionEnumCase->getValue();
137: }
138:
139: public function isDeprecated(): bool
140: {
141: return $this->betterReflectionEnumCase->isDeprecated();
142: }
143:
144: public function getValueExpression(): Expr
145: {
146: return $this->betterReflectionEnumCase->getValueExpression();
147: }
148:
149: public function __get(string $name): mixed
150: {
151: if ($name === 'name') {
152: return $this->betterReflectionEnumCase->getName();
153: }
154:
155: if ($name === 'class') {
156: return $this->betterReflectionEnumCase->getDeclaringClass()->getName();
157: }
158:
159: throw new OutOfBoundsException(sprintf('Property %s::$%s does not exist.', self::class, $name));
160: }
161: }
162: