|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
|
|
4
|
|
|
namespace ByJG\Config; |
|
5
|
|
|
|
|
6
|
|
|
use ByJG\Config\Exception\DependencyInjectionException; |
|
7
|
|
|
use Psr\Container\ContainerInterface; |
|
8
|
|
|
use ReflectionClass; |
|
9
|
|
|
use ReflectionException; |
|
10
|
|
|
use ReflectionMethod; |
|
11
|
|
|
|
|
12
|
|
|
class DependencyInjection |
|
13
|
|
|
{ |
|
14
|
|
|
/** |
|
15
|
|
|
* @var ContainerInterface |
|
16
|
|
|
*/ |
|
17
|
|
|
protected $containerInterface; |
|
18
|
|
|
|
|
19
|
|
|
protected $class; |
|
20
|
|
|
|
|
21
|
|
|
protected $args = []; |
|
22
|
|
|
|
|
23
|
|
|
protected $instance; |
|
24
|
|
|
|
|
25
|
|
|
protected $singleton = false; |
|
26
|
|
|
|
|
27
|
|
|
protected $methodCall = []; |
|
28
|
|
|
|
|
29
|
|
|
/** |
|
30
|
|
|
* @param $containerInterface ContainerInterface |
|
31
|
|
|
* @return DependencyInjection |
|
32
|
|
|
*/ |
|
33
|
|
|
public function injectContainer($containerInterface) |
|
34
|
|
|
{ |
|
35
|
|
|
$this->containerInterface = $containerInterface; |
|
36
|
|
|
return $this; |
|
37
|
|
|
} |
|
38
|
|
|
|
|
39
|
|
|
/** |
|
40
|
|
|
* @return mixed |
|
41
|
|
|
*/ |
|
42
|
|
|
protected function getClass() |
|
43
|
|
|
{ |
|
44
|
|
|
return $this->class; |
|
45
|
|
|
} |
|
46
|
|
|
|
|
47
|
|
|
/** |
|
48
|
|
|
* @param mixed $class |
|
49
|
|
|
* @throws DependencyInjectionException |
|
50
|
|
|
*/ |
|
51
|
|
|
protected function setClass($class) |
|
52
|
|
|
{ |
|
53
|
|
|
if (!class_exists($class)) { |
|
54
|
|
|
throw new DependencyInjectionException("Class $class does not exists"); |
|
55
|
|
|
} |
|
56
|
|
|
$this->class = $class; |
|
57
|
|
|
} |
|
58
|
|
|
|
|
59
|
|
|
/** |
|
60
|
|
|
* @return mixed |
|
61
|
|
|
*/ |
|
62
|
|
|
protected function getArgs() |
|
63
|
|
|
{ |
|
64
|
|
|
return array_map(function ($value) { |
|
65
|
|
|
if ($value instanceof Param) { |
|
66
|
|
|
return $this->containerInterface->get($value->getParam()); |
|
67
|
|
|
} |
|
68
|
|
|
return $value; |
|
69
|
|
|
}, $this->args); |
|
70
|
|
|
} |
|
71
|
|
|
|
|
72
|
|
|
/** |
|
73
|
|
|
* @param mixed $args |
|
74
|
|
|
* @return DependencyInjection |
|
75
|
|
|
* @throws DependencyInjectionException |
|
76
|
|
|
*/ |
|
77
|
|
|
public function withConstructorArgs($args) |
|
78
|
|
|
{ |
|
79
|
|
|
if (!is_null($args) && !is_array($args)) { |
|
80
|
|
|
throw new DependencyInjectionException("Arguments should be an array"); |
|
81
|
|
|
} |
|
82
|
|
|
$this->args = $args; |
|
|
|
|
|
|
83
|
|
|
|
|
84
|
|
|
return $this; |
|
85
|
|
|
} |
|
86
|
|
|
|
|
87
|
|
|
/** |
|
88
|
|
|
* DependencyInjection constructor. |
|
89
|
|
|
* @param $class |
|
90
|
|
|
* @throws DependencyInjectionException |
|
91
|
|
|
*/ |
|
92
|
|
|
protected function __construct($class) |
|
93
|
|
|
{ |
|
94
|
|
|
$this->setClass($class); |
|
95
|
|
|
} |
|
96
|
|
|
|
|
97
|
|
|
/** |
|
98
|
|
|
* @param $class |
|
99
|
|
|
* @return DependencyInjection |
|
100
|
|
|
* @throws DependencyInjectionException |
|
101
|
|
|
*/ |
|
102
|
|
|
public static function bind($class) |
|
103
|
|
|
{ |
|
104
|
|
|
return new DependencyInjection($class); |
|
105
|
|
|
} |
|
106
|
|
|
|
|
107
|
|
|
/** |
|
108
|
|
|
* @return DependencyInjection |
|
109
|
|
|
* @throws DependencyInjectionException |
|
110
|
|
|
* @throws ReflectionException |
|
111
|
|
|
*/ |
|
112
|
|
|
public function withInjectedConstructor() |
|
113
|
|
|
{ |
|
114
|
|
|
$reflection = new ReflectionMethod($this->getClass(), "__construct"); |
|
115
|
|
|
|
|
116
|
|
|
$docComments = str_replace("\n", " ", $reflection->getDocComment()); |
|
117
|
|
|
|
|
118
|
|
|
$params = []; |
|
119
|
|
|
$result = preg_match_all('/@param\s+\$[\w_\d]+\s+([\d\w_\\\\]+)/', $docComments, $params); |
|
120
|
|
|
|
|
121
|
|
|
if ($result) { |
|
122
|
|
|
$args = []; |
|
123
|
|
|
foreach ($params[1] as $param) { |
|
124
|
|
|
$args[] = Param::get(ltrim($param, "\\")); |
|
125
|
|
|
} |
|
126
|
|
|
return $this->withConstructorArgs($args); |
|
127
|
|
|
} |
|
128
|
|
|
|
|
129
|
|
|
return $this->withNoConstructor(); |
|
130
|
|
|
} |
|
131
|
|
|
|
|
132
|
|
|
/** |
|
133
|
|
|
* @return DependencyInjection |
|
134
|
|
|
*/ |
|
135
|
|
|
public function withNoConstructor() |
|
136
|
|
|
{ |
|
137
|
|
|
$this->args = null; |
|
|
|
|
|
|
138
|
|
|
return $this; |
|
139
|
|
|
} |
|
140
|
|
|
|
|
141
|
|
|
public function withMethodCall($method, $args = []) |
|
142
|
|
|
{ |
|
143
|
|
|
$this->methodCall[$method] = $args; |
|
144
|
|
|
return $this; |
|
145
|
|
|
} |
|
146
|
|
|
|
|
147
|
|
|
/** |
|
148
|
|
|
* @return DependencyInjection |
|
149
|
|
|
*/ |
|
150
|
|
|
public function toSingleton() |
|
151
|
|
|
{ |
|
152
|
|
|
$this->singleton = true; |
|
153
|
|
|
return $this; |
|
154
|
|
|
} |
|
155
|
|
|
|
|
156
|
|
|
/** |
|
157
|
|
|
* @return DependencyInjection |
|
158
|
|
|
*/ |
|
159
|
|
|
public function toInstance() |
|
160
|
|
|
{ |
|
161
|
|
|
$this->singleton = false; |
|
162
|
|
|
return $this; |
|
163
|
|
|
} |
|
164
|
|
|
|
|
165
|
|
|
/** |
|
166
|
|
|
* @return object |
|
167
|
|
|
* @throws ReflectionException |
|
168
|
|
|
*/ |
|
169
|
|
|
public function getInstance() |
|
170
|
|
|
{ |
|
171
|
|
|
if ($this->singleton) { |
|
172
|
|
|
return $this->getSingletonInstace(); |
|
173
|
|
|
} |
|
174
|
|
|
|
|
175
|
|
|
return $this->getNewInstance(); |
|
176
|
|
|
|
|
177
|
|
|
} |
|
178
|
|
|
|
|
179
|
|
|
/** |
|
180
|
|
|
* @return object |
|
181
|
|
|
* @throws ReflectionException |
|
182
|
|
|
*/ |
|
183
|
|
|
protected function getNewInstance() |
|
184
|
|
|
{ |
|
185
|
|
|
$reflectionClass = new ReflectionClass($this->getClass()); |
|
186
|
|
|
|
|
187
|
|
|
if (is_null($this->args)) { |
|
188
|
|
|
return $this->callMethods($reflectionClass->newInstanceWithoutConstructor()); |
|
189
|
|
|
} |
|
190
|
|
|
|
|
191
|
|
|
return $this->callMethods($reflectionClass->newInstanceArgs($this->getArgs())); |
|
192
|
|
|
} |
|
193
|
|
|
|
|
194
|
|
|
/** |
|
195
|
|
|
* @param $instance |
|
196
|
|
|
* @return mixed |
|
197
|
|
|
*/ |
|
198
|
|
|
protected function callMethods($instance) |
|
199
|
|
|
{ |
|
200
|
|
|
foreach ($this->methodCall as $methodName => $args) { |
|
201
|
|
|
if (is_null($args)) { |
|
202
|
|
|
call_user_func([$instance, $methodName]); |
|
203
|
|
|
} else { |
|
204
|
|
|
call_user_func_array([$instance, $methodName], $args); |
|
205
|
|
|
} |
|
206
|
|
|
} |
|
207
|
|
|
|
|
208
|
|
|
return $instance; |
|
209
|
|
|
} |
|
210
|
|
|
|
|
211
|
|
|
/** |
|
212
|
|
|
* @return object |
|
213
|
|
|
* @throws ReflectionException |
|
214
|
|
|
*/ |
|
215
|
|
|
protected function getSingletonInstace() |
|
216
|
|
|
{ |
|
217
|
|
|
if (empty($this->instance)) { |
|
218
|
|
|
$this->instance = $this->getNewInstance(); |
|
219
|
|
|
} |
|
220
|
|
|
return $this->instance; |
|
221
|
|
|
} |
|
222
|
|
|
} |
|
223
|
|
|
|
Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.
To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.
The function can be called with either null or an array for the parameter
$needlebut will only accept an array as$haystack.