1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace PHPStan\BetterReflection\Reflection\Adapter;
6:
7: use ArgumentCountError;
8: use OutOfBoundsException;
9: use PhpParser\Node\Expr;
10: use ReflectionException as CoreReflectionException;
11: use ReflectionProperty as CoreReflectionProperty;
12: use ReturnTypeWillChange;
13: use PHPStan\BetterReflection\Reflection\Exception\NoObjectProvided;
14: use PHPStan\BetterReflection\Reflection\Exception\NotAnObject;
15: use PHPStan\BetterReflection\Reflection\ReflectionAttribute as BetterReflectionAttribute;
16: use PHPStan\BetterReflection\Reflection\ReflectionProperty as BetterReflectionProperty;
17: use Throwable;
18: use TypeError;
19: use ValueError;
20:
21: use function array_map;
22: use function gettype;
23: use function sprintf;
24:
25: final class ReflectionProperty extends CoreReflectionProperty
26: {
27: public const IS_READONLY = 128;
28: /**
29: * @var BetterReflectionProperty
30: */
31: private $betterReflectionProperty;
32:
33: public function __construct(BetterReflectionProperty $betterReflectionProperty)
34: {
35: $this->betterReflectionProperty = $betterReflectionProperty;
36: unset($this->name);
37: unset($this->class);
38: }
39:
40: public function __toString(): string
41: {
42: return $this->betterReflectionProperty->__toString();
43: }
44:
45: public function getName(): string
46: {
47: return $this->betterReflectionProperty->getName();
48: }
49:
50: /**
51: * {@inheritDoc}
52: * @return mixed
53: */
54: #[ReturnTypeWillChange]
55: public function getValue($object = null)
56: {
57: try {
58: return $this->betterReflectionProperty->getValue($object);
59: } catch (NoObjectProvided $exception) {
60: return null;
61: } catch (Throwable $e) {
62: throw new CoreReflectionException($e->getMessage(), 0, $e);
63: }
64: }
65:
66: /** @psalm-suppress MethodSignatureMismatch
67: * @param mixed $objectOrValue
68: * @param mixed $value */
69: public function setValue($objectOrValue, $value = null): void
70: {
71: try {
72: $this->betterReflectionProperty->setValue($objectOrValue, $value);
73: } catch (NoObjectProvided $exception) {
74: throw new ArgumentCountError('ReflectionProperty::setValue() expects exactly 2 arguments, 1 given');
75: } catch (NotAnObject $exception) {
76: throw new TypeError(sprintf('ReflectionProperty::setValue(): Argument #1 ($objectOrValue) must be of type object, %s given', gettype($objectOrValue)));
77: } catch (Throwable $e) {
78: throw new CoreReflectionException($e->getMessage(), 0, $e);
79: }
80: }
81:
82: public function hasType(): bool
83: {
84: return $this->betterReflectionProperty->hasType();
85: }
86:
87: /**
88: * @return ReflectionUnionType|ReflectionNamedType|ReflectionIntersectionType|null
89: */
90: public function getType(): ?\ReflectionType
91: {
92: return ReflectionType::fromTypeOrNull($this->betterReflectionProperty->getType());
93: }
94:
95: public function isPublic(): bool
96: {
97: return $this->betterReflectionProperty->isPublic();
98: }
99:
100: public function isPrivate(): bool
101: {
102: return $this->betterReflectionProperty->isPrivate();
103: }
104:
105: public function isProtected(): bool
106: {
107: return $this->betterReflectionProperty->isProtected();
108: }
109:
110: public function isStatic(): bool
111: {
112: return $this->betterReflectionProperty->isStatic();
113: }
114:
115: public function isDefault(): bool
116: {
117: return $this->betterReflectionProperty->isDefault();
118: }
119:
120: public function getModifiers(): int
121: {
122: return $this->betterReflectionProperty->getModifiers();
123: }
124:
125: public function getDeclaringClass(): ReflectionClass
126: {
127: return new ReflectionClass($this->betterReflectionProperty->getImplementingClass());
128: }
129:
130: /**
131: * {@inheritDoc}
132: */
133: #[ReturnTypeWillChange]
134: public function getDocComment()
135: {
136: return $this->betterReflectionProperty->getDocComment() ?? false;
137: }
138:
139: /**
140: * {@inheritDoc}
141: * @codeCoverageIgnore
142: * @infection-ignore-all
143: */
144: public function setAccessible($accessible): void
145: {
146: }
147:
148: public function hasDefaultValue(): bool
149: {
150: return $this->betterReflectionProperty->hasDefaultValue();
151: }
152:
153: /**
154: * @deprecated Use getDefaultValueExpression()
155: * @return mixed
156: */
157: #[ReturnTypeWillChange]
158: public function getDefaultValue()
159: {
160: return $this->betterReflectionProperty->getDefaultValue();
161: }
162:
163: /**
164: * @deprecated Use getDefaultValueExpression()
165: */
166: public function getDefaultValueExpr(): Expr
167: {
168: return $this->betterReflectionProperty->getDefaultValueExpression();
169: }
170:
171: public function getDefaultValueExpression(): Expr
172: {
173: return $this->betterReflectionProperty->getDefaultValueExpression();
174: }
175:
176: /**
177: * {@inheritDoc}
178: */
179: #[ReturnTypeWillChange]
180: public function isInitialized($object = null)
181: {
182: try {
183: return $this->betterReflectionProperty->isInitialized($object);
184: } catch (Throwable $e) {
185: throw new CoreReflectionException($e->getMessage(), 0, $e);
186: }
187: }
188:
189: public function isPromoted(): bool
190: {
191: return $this->betterReflectionProperty->isPromoted();
192: }
193:
194: /**
195: * @param class-string|null $name
196: *
197: * @return list<ReflectionAttribute|FakeReflectionAttribute>
198: */
199: public function getAttributes(?string $name = null, int $flags = 0): array
200: {
201: if ($flags !== 0 && $flags !== ReflectionAttribute::IS_INSTANCEOF) {
202: throw new ValueError('Argument #2 ($flags) must be a valid attribute filter flag');
203: }
204:
205: if ($name !== null && $flags !== 0) {
206: $attributes = $this->betterReflectionProperty->getAttributesByInstance($name);
207: } elseif ($name !== null) {
208: $attributes = $this->betterReflectionProperty->getAttributesByName($name);
209: } else {
210: $attributes = $this->betterReflectionProperty->getAttributes();
211: }
212:
213: return array_map(static function (BetterReflectionAttribute $betterReflectionAttribute) {
214: return ReflectionAttributeFactory::create($betterReflectionAttribute);
215: }, $attributes);
216: }
217:
218: public function isReadOnly(): bool
219: {
220: return $this->betterReflectionProperty->isReadOnly();
221: }
222:
223: /**
224: * @return mixed
225: */
226: public function __get(string $name)
227: {
228: if ($name === 'name') {
229: return $this->betterReflectionProperty->getName();
230: }
231:
232: if ($name === 'class') {
233: return $this->betterReflectionProperty->getImplementingClass()->getName();
234: }
235:
236: throw new OutOfBoundsException(sprintf('Property %s::$%s does not exist.', self::class, $name));
237: }
238:
239: public function getBetterReflection(): BetterReflectionProperty
240: {
241: return $this->betterReflectionProperty;
242: }
243: }
244: