schemator-php
289 строк · 7.8 Кб
1<?php
2
3declare(strict_types=1);
4
5namespace Smoren\Schemator\Helpers;
6
7use ReflectionMethod;
8use ReflectionProperty;
9use Smoren\Schemator\Interfaces\ProxyInterface;
10use Smoren\Schemator\Structs\ObjectPropertyProxy;
11use stdClass;
12
13/**
14* Tool for reflecting and accessing object properties and methods.
15*/
16class ObjectAccessHelper
17{
18/**
19* Returns value of the object property.
20*
21* Can access property by its name or by getter.
22*
23* @param object $object
24* @param string $propertyName
25*
26* @return mixed
27*
28* @throws \InvalidArgumentException
29*/
30public static function getPropertyValue(object $object, string $propertyName)
31{
32if (static::hasPropertyAccessibleByGetter($object, $propertyName)) {
33return static::getPropertyValueByGetter($object, $propertyName);
34}
35
36if (static::hasPublicProperty($object, $propertyName)) {
37return $object->{$propertyName};
38}
39
40$className = get_class($object);
41throw new \InvalidArgumentException("Property '{$className}::{$propertyName}' is not readable");
42}
43
44/**
45* Returns reference to the object property.
46*
47* @param object $object
48* @param string $propertyName
49* @param mixed $defaultValue
50*
51* @return mixed|ProxyInterface<object>
52*
53* @throws \InvalidArgumentException
54*/
55public static function &getPropertyRef(object &$object, string $propertyName, $defaultValue = null)
56{
57if (static::hasPublicProperty($object, $propertyName)) {
58return $object->{$propertyName};
59}
60
61if ($object instanceof stdClass) {
62$object->{$propertyName} = $defaultValue;
63return $object->{$propertyName};
64}
65
66$proxy = new ObjectPropertyProxy($object, $propertyName);
67return $proxy;
68}
69
70/**
71* Returns value of the object property.
72*
73* Can access property by its name or by getter.
74*
75* @param object $object
76* @param string $propertyName
77* @param mixed $value
78*
79* @return void
80*
81* @throws \InvalidArgumentException
82*/
83public static function setPropertyValue(object $object, string $propertyName, $value): void
84{
85if (static::hasPropertyAccessibleBySetter($object, $propertyName)) {
86static::setPropertyValueBySetter($object, $propertyName, $value);
87return;
88}
89
90if (static::hasPublicProperty($object, $propertyName) || $object instanceof stdClass) {
91$object->{$propertyName} = $value;
92return;
93}
94
95$className = get_class($object);
96throw new \InvalidArgumentException("Property '{$className}::{$propertyName}' is not writable");
97}
98
99/**
100* Returns true if object has property that is accessible to read by name or by getter.
101*
102* @param object $object
103* @param string $propertyName
104*
105* @return bool
106*/
107public static function hasReadableProperty(object $object, string $propertyName): bool
108{
109return static::hasPublicProperty($object, $propertyName)
110|| static::hasPropertyAccessibleByGetter($object, $propertyName);
111}
112
113/**
114* Returns true if object has property that is accessible to write by name or by setter.
115*
116* @param object $object
117* @param string $propertyName
118*
119* @return bool
120*/
121public static function hasWritableProperty(object $object, string $propertyName): bool
122{
123return static::hasPublicProperty($object, $propertyName)
124|| static::hasPropertyAccessibleBySetter($object, $propertyName);
125}
126
127/**
128* Returns true if object has public property.
129*
130* @param object $object
131* @param string $propertyName
132*
133* @return bool
134*/
135public static function hasPublicProperty(object $object, string $propertyName): bool
136{
137if ($object instanceof stdClass) {
138return static::hasProperty($object, $propertyName);
139}
140
141return
142static::hasProperty($object, $propertyName) &&
143static::getReflectionProperty($object, $propertyName)->isPublic();
144}
145
146/**
147* Returns true if object has property.
148*
149* @param object $object
150* @param string $propertyName
151*
152* @return bool
153*/
154public static function hasProperty(object $object, string $propertyName): bool
155{
156return property_exists($object, $propertyName);
157}
158
159/**
160* Returns true if object has public method.
161*
162* @param object $object
163* @param string $methodName
164*
165* @return bool
166*/
167public static function hasPublicMethod(object $object, string $methodName): bool
168{
169return
170static::hasMethod($object, $methodName) &&
171static::getReflectionMethod($object, $methodName)->isPublic();
172}
173
174/**
175* Returns true if object has method.
176*
177* @param object $object
178* @param string $methodName
179*
180* @return bool
181*/
182public static function hasMethod(object $object, string $methodName): bool
183{
184return method_exists($object, $methodName);
185}
186
187/**
188* Returns true if object has property that is accessible by getter.
189*
190* @param object $object
191* @param string $propertyName
192*
193* @return bool
194*/
195protected static function hasPropertyAccessibleByGetter(object $object, string $propertyName): bool
196{
197return static::hasPublicMethod($object, static::getPropertyGetterName($propertyName));
198}
199
200/**
201* Returns true if object has property that is accessible by setter.
202*
203* @param object $object
204* @param string $propertyName
205*
206* @return bool
207*/
208protected static function hasPropertyAccessibleBySetter(object $object, string $propertyName): bool
209{
210return static::hasPublicMethod($object, static::getPropertySetterName($propertyName));
211}
212
213/**
214* Returns property value by getter.
215*
216* @param object $object
217* @param string $propertyName
218*
219* @return mixed
220*/
221protected static function getPropertyValueByGetter(object $object, string $propertyName)
222{
223return $object->{static::getPropertyGetterName($propertyName)}();
224}
225
226/**
227* Sets property value by setter.
228*
229* @param object $object
230* @param string $propertyName
231* @param mixed $value
232*
233* @return void
234*/
235protected static function setPropertyValueBySetter(object $object, string $propertyName, $value): void
236{
237$object->{static::getPropertySetterName($propertyName)}($value);
238}
239
240/**
241* Returns reflection object of the object property.
242*
243* @param object $object
244* @param string $propertyName
245*
246* @return ReflectionProperty
247*/
248protected static function getReflectionProperty(object $object, string $propertyName): ReflectionProperty
249{
250return new ReflectionProperty(get_class($object), $propertyName);
251}
252
253/**
254* Returns reflection object of the object method.
255*
256* @param object $object
257* @param string $methodName
258*
259* @return ReflectionMethod
260*/
261protected static function getReflectionMethod(object $object, string $methodName): ReflectionMethod
262{
263return new ReflectionMethod(get_class($object), $methodName);
264}
265
266/**
267* Returns property getter name.
268*
269* @param string $propertyName
270*
271* @return string
272*/
273protected static function getPropertyGetterName(string $propertyName): string
274{
275return 'get' . ucfirst($propertyName);
276}
277
278/**
279* Returns property setter name.
280*
281* @param string $propertyName
282*
283* @return string
284*/
285protected static function getPropertySetterName(string $propertyName): string
286{
287return 'set' . ucfirst($propertyName);
288}
289}
290