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 ReflectionClassConstant as CoreReflectionClassConstant;
10: use ReflectionType as CoreReflectionType;
11: use ReturnTypeWillChange;
12: use PHPStan\BetterReflection\Reflection\ReflectionAttribute as BetterReflectionAttribute;
13: use PHPStan\BetterReflection\Reflection\ReflectionClassConstant as BetterReflectionClassConstant;
14: use PHPStan\BetterReflection\Reflection\ReflectionEnumCase as BetterReflectionEnumCase;
15: use ValueError;
16:
17: use function array_map;
18: use function constant;
19: use function sprintf;
20:
21: /**
22: * @psalm-suppress PropertyNotSetInConstructor
23: * @psalm-immutable
24: */
25: final class ReflectionClassConstant extends CoreReflectionClassConstant
26: {
27: public const IS_PUBLIC = 1;
28:
29: public const IS_PROTECTED = 2;
30:
31: public const IS_PRIVATE = 4;
32:
33: public const IS_FINAL = 32;
34: /**
35: * @var BetterReflectionClassConstant|BetterReflectionEnumCase
36: */
37: private $betterClassConstantOrEnumCase;
38:
39: /**
40: * @param BetterReflectionClassConstant|BetterReflectionEnumCase $betterClassConstantOrEnumCase
41: */
42: public function __construct($betterClassConstantOrEnumCase)
43: {
44: $this->betterClassConstantOrEnumCase = $betterClassConstantOrEnumCase;
45: unset($this->name);
46: unset($this->class);
47: }
48:
49: public function getName(): string
50: {
51: return $this->betterClassConstantOrEnumCase->getName();
52: }
53:
54: /** @psalm-mutation-free */
55: public function hasType(): bool
56: {
57: if ($this->betterClassConstantOrEnumCase instanceof BetterReflectionEnumCase) {
58: return false;
59: }
60:
61: return $this->betterClassConstantOrEnumCase->hasType();
62: }
63:
64: /**
65: * @psalm-mutation-free
66: * @return ReflectionUnionType|ReflectionNamedType|ReflectionIntersectionType|null
67: */
68: public function getType(): ?CoreReflectionType
69: {
70: if ($this->betterClassConstantOrEnumCase instanceof BetterReflectionEnumCase) {
71: return null;
72: }
73:
74: return ReflectionType::fromTypeOrNull($this->betterClassConstantOrEnumCase->getType());
75: }
76:
77: /**
78: * @deprecated Use getValueExpression()
79: */
80: #[ReturnTypeWillChange]
81: public function getValue()
82: {
83: if ($this->betterClassConstantOrEnumCase instanceof BetterReflectionEnumCase) {
84: throw new Exception\NotImplemented('Not implemented');
85: }
86:
87: return $this->betterClassConstantOrEnumCase->getValue();
88: }
89:
90: /**
91: * @deprecated Use getValueExpression()
92: */
93: public function getValueExpr(): Expr
94: {
95: return $this->getValueExpression();
96: }
97:
98: public function getValueExpression(): Expr
99: {
100: return $this->betterClassConstantOrEnumCase->getValueExpression();
101: }
102:
103: public function isPublic(): bool
104: {
105: if ($this->betterClassConstantOrEnumCase instanceof BetterReflectionEnumCase) {
106: return true;
107: }
108:
109: return $this->betterClassConstantOrEnumCase->isPublic();
110: }
111:
112: public function isPrivate(): bool
113: {
114: if ($this->betterClassConstantOrEnumCase instanceof BetterReflectionEnumCase) {
115: return false;
116: }
117:
118: return $this->betterClassConstantOrEnumCase->isPrivate();
119: }
120:
121: public function isProtected(): bool
122: {
123: if ($this->betterClassConstantOrEnumCase instanceof BetterReflectionEnumCase) {
124: return false;
125: }
126:
127: return $this->betterClassConstantOrEnumCase->isProtected();
128: }
129:
130: public function getModifiers(): int
131: {
132: if ($this->betterClassConstantOrEnumCase instanceof BetterReflectionEnumCase) {
133: return ReflectionClassConstant::IS_PUBLIC;
134: }
135:
136: return $this->betterClassConstantOrEnumCase->getModifiers();
137: }
138:
139: public function getDeclaringClass(): ReflectionClass
140: {
141: if ($this->betterClassConstantOrEnumCase instanceof BetterReflectionEnumCase) {
142: return new ReflectionClass($this->betterClassConstantOrEnumCase->getDeclaringClass());
143: }
144:
145: return new ReflectionClass($this->betterClassConstantOrEnumCase->getImplementingClass());
146: }
147:
148: /**
149: * Returns the doc comment for this constant
150: *
151: * @return string|false
152: */
153: #[ReturnTypeWillChange]
154: public function getDocComment()
155: {
156: return $this->betterClassConstantOrEnumCase->getDocComment() ?? false;
157: }
158:
159: /**
160: * To string
161: *
162: * @link https://php.net/manual/en/reflector.tostring.php
163: *
164: * @return non-empty-string
165: */
166: public function __toString(): string
167: {
168: return $this->betterClassConstantOrEnumCase->__toString();
169: }
170:
171: /**
172: * @param class-string|null $name
173: *
174: * @return list<ReflectionAttribute|FakeReflectionAttribute>
175: */
176: public function getAttributes(?string $name = null, int $flags = 0): array
177: {
178: if ($flags !== 0 && $flags !== ReflectionAttribute::IS_INSTANCEOF) {
179: throw new ValueError('Argument #2 ($flags) must be a valid attribute filter flag');
180: }
181:
182: if ($name !== null && $flags !== 0) {
183: $attributes = $this->betterClassConstantOrEnumCase->getAttributesByInstance($name);
184: } elseif ($name !== null) {
185: $attributes = $this->betterClassConstantOrEnumCase->getAttributesByName($name);
186: } else {
187: $attributes = $this->betterClassConstantOrEnumCase->getAttributes();
188: }
189:
190: /** @psalm-suppress ImpureFunctionCall */
191: return array_map(static function (BetterReflectionAttribute $betterReflectionAttribute) {
192: return ReflectionAttributeFactory::create($betterReflectionAttribute);
193: }, $attributes);
194: }
195:
196: public function isFinal(): bool
197: {
198: if ($this->betterClassConstantOrEnumCase instanceof BetterReflectionEnumCase) {
199: return true;
200: }
201:
202: return $this->betterClassConstantOrEnumCase->isFinal();
203: }
204:
205: public function isEnumCase(): bool
206: {
207: return $this->betterClassConstantOrEnumCase instanceof BetterReflectionEnumCase;
208: }
209:
210: /**
211: * @return mixed
212: */
213: public function __get(string $name)
214: {
215: if ($name === 'name') {
216: return $this->betterClassConstantOrEnumCase->getName();
217: }
218:
219: if ($name === 'class') {
220: return $this->getDeclaringClass()->getName();
221: }
222:
223: throw new OutOfBoundsException(sprintf('Property %s::$%s does not exist.', self::class, $name));
224: }
225: }
226: