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