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 hasType(): bool
40: {
41: return false;
42: }
43:
44: public function getType(): ?ReflectionType
45: {
46: return null;
47: }
48:
49: public function getValue(): UnitEnum
50: {
51: throw new Exception\NotImplemented('Not implemented');
52: }
53:
54: public function isPublic(): bool
55: {
56: return true;
57: }
58:
59: public function isPrivate(): bool
60: {
61: return false;
62: }
63:
64: public function isProtected(): bool
65: {
66: return false;
67: }
68:
69: public function getModifiers(): int
70: {
71: return self::IS_PUBLIC;
72: }
73:
74: public function getDeclaringClass(): ReflectionClass
75: {
76: return new ReflectionClass($this->betterReflectionEnumCase->getDeclaringClass());
77: }
78:
79: public function getDocComment(): string|false
80: {
81: return $this->betterReflectionEnumCase->getDocComment() ?? false;
82: }
83:
84: /** @return non-empty-string */
85: public function __toString(): string
86: {
87: return $this->betterReflectionEnumCase->__toString();
88: }
89:
90: /**
91: * @param class-string|null $name
92: *
93: * @return list<ReflectionAttribute|FakeReflectionAttribute>
94: */
95: public function getAttributes(string|null $name = null, int $flags = 0): array
96: {
97: if ($flags !== 0 && $flags !== ReflectionAttribute::IS_INSTANCEOF) {
98: throw new ValueError('Argument #2 ($flags) must be a valid attribute filter flag');
99: }
100:
101: if ($name !== null && $flags !== 0) {
102: $attributes = $this->betterReflectionEnumCase->getAttributesByInstance($name);
103: } elseif ($name !== null) {
104: $attributes = $this->betterReflectionEnumCase->getAttributesByName($name);
105: } else {
106: $attributes = $this->betterReflectionEnumCase->getAttributes();
107: }
108:
109: /** @psalm-suppress ImpureFunctionCall */
110: return array_map(static fn (BetterReflectionAttribute $betterReflectionAttribute): ReflectionAttribute|FakeReflectionAttribute => ReflectionAttributeFactory::create($betterReflectionAttribute), $attributes);
111: }
112:
113: public function isFinal(): bool
114: {
115: return true;
116: }
117:
118: public function isEnumCase(): bool
119: {
120: return true;
121: }
122:
123: public function getEnum(): ReflectionEnum
124: {
125: return new ReflectionEnum($this->betterReflectionEnumCase->getDeclaringEnum());
126: }
127:
128: public function getBackingValue(): int|string
129: {
130: return $this->betterReflectionEnumCase->getValue();
131: }
132:
133: public function getValueExpression(): Expr
134: {
135: return $this->betterReflectionEnumCase->getValueExpression();
136: }
137:
138: public function __get(string $name): mixed
139: {
140: if ($name === 'name') {
141: return $this->betterReflectionEnumCase->getName();
142: }
143:
144: if ($name === 'class') {
145: return $this->betterReflectionEnumCase->getDeclaringClass()->getName();
146: }
147:
148: throw new OutOfBoundsException(sprintf('Property %s::$%s does not exist.', self::class, $name));
149: }
150: }
151: