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