Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
Container.php
1<?php
2
4
7use ReflectionNamedType;
8
17final class Container implements ContainerContract
18{
19 private $dependencies = [];
20 private $entities = [];
21
22 private $lock = false;
23
24 public function __construct()
25 {
26 $this->dependencies[static::class] = static::class;
27 $this->dependencies[ContainerContract::class] = static::class;
28 }
29
30 private function __clone()
31 {
32 }
33
34 public function has(string $id): bool
35 {
36 return isset($this->dependencies[$id]);
37 }
38
39 public function get(string $id, array $args = [])
40 {
41 if (!$this->has($id))
42 {
43 throw new ObjectNotFoundException("Dependency {{$id}} not found.");
44 }
45
46 $definition = $this->getDefinition($id, $args);
47
48 if (!isset($this->entities[$definition]))
49 {
50 $this->entities[$definition] = $this->instantiate($id, $args);
51 }
52
53 return $this->entities[$definition];
54 }
55
56 // ToDo highlight container return values with phpstorm.meta.php
57 public function make(string $id, array $args = [])
58 {
59 if (!$this->has($id))
60 {
61 throw new ObjectNotFoundException("Dependency {{$id}} not found.");
62 }
63
64 return $this->instantiate($id, $args);
65 }
66
67 public function inject(string $id, $dependency): ContainerContract
68 {
69 if ($this->isLocked())
70 {
71 throw new NotSupportedException(
72 "Dependency {{$dependency}} cannot be injected after resolving container dependencies.
73 Try this before resolving."
74 );
75 }
76
77 $this->dependencies[$id] = $dependency;
78
79 if (!isset($this->dependencies[$dependency]) && class_exists($dependency))
80 {
81 $this->dependencies[$dependency] = $dependency;
82 }
83
84 unset($this->entities[$id]);
85
86 return $this;
87 }
88
89 public function getIterator(): \ArrayIterator
90 {
91 return new \ArrayIterator($this->dependencies);
92 }
93
94 private function instantiate($id, array $args = [])
95 {
96 $this->lock();
97
98 $dependency = $this->dependencies[$id];
99
100 if ($dependency instanceof \Closure)
101 {
102 $entity = $this->instantiateClosure($dependency, $args);
103 }
104 elseif (class_exists($dependency))
105 {
106 $entity = $this->instantiateClass($dependency, $args);
107 }
108 else
109 {
110 $entity = $dependency;
111 }
112
113 return $entity;
114 }
115
116 private function instantiateClosure($dependency, array $args = [])
117 {
118 $function = new \ReflectionFunction($dependency);
119
120 $invokeArguments = [];
121
122 foreach ($function->getParameters() as $parameter)
123 {
124 $invokeArguments[] = $this->resolveParameter($parameter, $args);
125 }
126
127 return $function->invokeArgs($invokeArguments);
128 }
129
130 private function instantiateClass($dependency, array $args = [])
131 {
132 $class = new \ReflectionClass($dependency);
133 $constructor = $class->getConstructor();
134
135 if ($constructor)
136 {
137 $invokeArguments = [];
138
139 foreach ($constructor->getParameters() as $parameter)
140 {
141 $invokeArguments[] = $this->resolveParameter($parameter, $args);
142 }
143
144 return $class->newInstance(...$invokeArguments);
145 }
146
147 return $class->newInstanceWithoutConstructor();
148 }
149
150 private function resolveParameter(\ReflectionParameter $parameter, array $args = [])
151 {
152 $type = $parameter->getType();
153 if (($type instanceof ReflectionNamedType) && !$type->isBuiltin())
154 {
155 return $this->resolveClassParameter($parameter, $args);
156 }
157
158 return $this->resolveVariableParameter($parameter, $args);
159 }
160
161 private function resolveClassParameter(\ReflectionParameter $parameter, array $args = [])
162 {
163 try
164 {
165 $type = $parameter->getType();
166 if (($type instanceof ReflectionNamedType) && !$type->isBuiltin())
167 {
168 $className = $type->getName();
169 }
170 else
171 {
172 throw new ObjectNotFoundException('Not class type');
173 }
174
175 if ($className === static::class || is_subclass_of(static::class, $className))
176 {
177 return $this;
178 }
179
180 $dependency = $args[$className] ?? $this->get($className, $args);
181 }
182 catch (ObjectNotFoundException $exception)
183 {
184 if ($parameter->isDefaultValueAvailable())
185 {
186 $dependency = $parameter->getDefaultValue();
187 }
188 else
189 {
190 $name = $parameter->getName();
191 throw new ObjectNotFoundException("Dependency {{$name}} not found.");
192 }
193 }
194
195 return $dependency;
196 }
197
198 private function resolveVariableParameter(\ReflectionParameter $parameter, array $args = [])
199 {
200 $parameterName = $parameter->getName();
201
202 if (isset($args[$parameterName]))
203 {
204 return $args[$parameterName];
205 }
206
207 if ($parameter->isDefaultValueAvailable())
208 {
209 return $parameter->getDefaultValue();
210 }
211
212 return null;
213 }
214
215 private function lock(): self
216 {
217 $this->lock = true;
218
219 return $this;
220 }
221
222 private function isLocked(): bool
223 {
224 return $this->lock;
225 }
226
227 private function getDefinition(string $id, array $args = []): string
228 {
229 if (empty($args))
230 {
231 return $id;
232 }
233
234 ksort($args);
235 $argString = '';
236
237 foreach ($args as $key => $argument)
238 {
239 if (is_object($argument))
240 {
241 $argument = spl_object_hash($argument);
242 }
243
244 $argString .= "|$key=$argument";
245 }
246
247 return $id . $argString;
248 }
249}
inject(string $id, $dependency)
Definition Container.php:67
make(string $id, array $args=[])
Definition Container.php:57