1
|
|
|
<?php |
2
|
|
|
namespace MetaHydrator\Reflection; |
3
|
|
|
|
4
|
|
|
use ArrayAccess; |
5
|
|
|
use ReflectionClass; |
6
|
|
|
use ReflectionException; |
7
|
|
|
use ReflectionMethod; |
8
|
|
|
|
9
|
|
|
class Getter implements GetterInterface |
10
|
|
|
{ |
11
|
|
|
/** @var bool */ |
12
|
|
|
protected $throwOnFail; |
13
|
|
|
|
14
|
|
|
/** @var bool */ |
15
|
|
|
protected $ignoreProtected; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Getter constructor. |
19
|
|
|
* @param bool $throwOnFail |
20
|
|
|
* @param bool $ignoreProtected |
21
|
|
|
*/ |
22
|
|
|
public function __construct(bool $throwOnFail = true, bool $ignoreProtected = false) |
23
|
|
|
{ |
24
|
|
|
$this->throwOnFail = $throwOnFail; |
25
|
|
|
$this->ignoreProtected = $ignoreProtected; |
26
|
|
|
} |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* @param $object |
30
|
|
|
* @param string $field |
31
|
|
|
* @return mixed |
32
|
|
|
*/ |
33
|
|
View Code Duplication |
public function get($object, string $field) |
|
|
|
|
34
|
|
|
{ |
35
|
|
|
if (is_array($object)) { |
36
|
|
|
return $this->getFromArray($object, $field); |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
if (is_object($object)) { |
40
|
|
|
return $this->getFromObject($object, $field); |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
if ($this->throwOnFail) { |
44
|
|
|
throw new ReflectionException("cannot extract field '$field' from non-object, non-array value"); |
45
|
|
|
} else { |
46
|
|
|
return null; |
47
|
|
|
} |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* @param $object |
52
|
|
|
* @param string $field |
53
|
|
|
* @return null |
54
|
|
|
* @throws ReflectionException |
55
|
|
|
*/ |
56
|
|
|
protected function getFromArray($object, string $field) |
57
|
|
|
{ |
58
|
|
|
if (array_key_exists($field, $object)) { |
59
|
|
|
return $object[$field]; |
60
|
|
|
} else if ($this->throwOnFail) { |
61
|
|
|
throw new ReflectionException("cannot extract field '$field' from array"); |
62
|
|
|
} else { |
63
|
|
|
return null; |
64
|
|
|
} |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* @param $object |
69
|
|
|
* @param string $field |
70
|
|
|
* @return mixed|null |
71
|
|
|
* @throws ReflectionException |
72
|
|
|
*/ |
73
|
|
View Code Duplication |
protected function getFromObject($object, string $field) |
|
|
|
|
74
|
|
|
{ |
75
|
|
|
$reflectionClass = new ReflectionClass($object); |
76
|
|
|
|
77
|
|
|
$getterMethod = $this->findGetterMethod($reflectionClass, $field); |
78
|
|
|
if ($getterMethod !== null) { |
79
|
|
|
return $getterMethod->invoke($object); |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
$property = $this->findProperty($reflectionClass, $field); |
83
|
|
|
if ($property !== null) { |
84
|
|
|
return $property->getValue($object); |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
if ($object instanceof ArrayAccess && $object->offsetExists($field)) { |
88
|
|
|
return $object->offsetGet($field); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
if ($this->throwOnFail) { |
92
|
|
|
throw new ReflectionException("cannot extract field '$field' from object"); |
93
|
|
|
} else { |
94
|
|
|
return null; |
95
|
|
|
} |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* @param ReflectionClass $reflectionClass |
100
|
|
|
* @param string $field |
101
|
|
|
* @return null|ReflectionMethod |
102
|
|
|
*/ |
103
|
|
View Code Duplication |
protected function findGetterMethod(ReflectionClass $reflectionClass, string $field) |
|
|
|
|
104
|
|
|
{ |
105
|
|
|
foreach ($reflectionClass->getMethods($this->ignoreProtected ? ReflectionMethod::IS_PUBLIC|ReflectionMethod::IS_PROTECTED|ReflectionMethod::IS_PRIVATE : ReflectionMethod::IS_PUBLIC) as $reflectionMethod) { |
106
|
|
|
if (!$reflectionMethod->isStatic() |
107
|
|
|
&& $reflectionMethod->getNumberOfRequiredParameters() == 0 |
108
|
|
|
&& strcasecmp($reflectionMethod->getName(), "get$field") == 0) { |
|
|
|
|
109
|
|
|
if (!$reflectionMethod->isPublic()) { |
110
|
|
|
$reflectionMethod->setAccessible(true); |
111
|
|
|
} |
112
|
|
|
return $reflectionMethod; |
113
|
|
|
} |
114
|
|
|
} |
115
|
|
|
return null; |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* @param ReflectionClass $reflectionClass |
120
|
|
|
* @param string $field |
121
|
|
|
* @return null|\ReflectionProperty |
122
|
|
|
*/ |
123
|
|
View Code Duplication |
protected function findProperty(ReflectionClass $reflectionClass, string $field) |
|
|
|
|
124
|
|
|
{ |
125
|
|
|
if ($reflectionClass->hasProperty($field)) { |
126
|
|
|
$property = $reflectionClass->getProperty($field); |
127
|
|
|
if (!$property->isStatic()) { |
128
|
|
|
if ($property->isPublic()) { |
129
|
|
|
return $property; |
130
|
|
|
} else if ($this->ignoreProtected) { |
131
|
|
|
$property->setAccessible(true); |
132
|
|
|
return $property; |
133
|
|
|
} |
134
|
|
|
} |
135
|
|
|
} |
136
|
|
|
return null; |
137
|
|
|
} |
138
|
|
|
} |
139
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.