Passed
Branch master (e2a001)
by Alex
07:16 queued 03:47
created
src/Container.php 2 patches
Indentation   +435 added lines, -435 removed lines patch added patch discarded remove patch
@@ -25,440 +25,440 @@
 block discarded – undo
25 25
 class Container implements ContainerInterface
26 26
 {
27 27
 
28
-    /**
29
-     * Holds all resolved or resolvable instances into the container.
30
-     *
31
-     * @var array
32
-     */
33
-
34
-    protected $collection;
35
-
36
-    /**
37
-     * Class specific defined dependencies.
38
-     *
39
-     * @var array
40
-     */
41
-
42
-    protected $dependencies;
43
-
44
-    /**
45
-     * Cache of classes inspector and resolver.
46
-     *
47
-     * @var array
48
-     */
49
-
50
-    protected $resolving;
51
-
52
-    /**
53
-     * Cache of classes dependencies in callbacks ready for resolution.
54
-     *
55
-     * @var array
56
-     */
57
-
58
-    protected $resolved;
59
-
60
-    /**
61
-     * Call a user function injecting the dependencies.
62
-     *
63
-     * @param string|Closure $function   The function or the user function name.
64
-     * @param array          $parameters The predefined dependencies.
65
-     *
66
-     * @return mixed
67
-     */
68
-
69
-    public function call($function, array $parameters = [])
70
-    {
71
-        $inspector = new ReflectionFunction($function);
72
-
73
-        $dependencies = $inspector->getParameters();
74
-        $dependencies = $this->process('', $parameters, $dependencies);
75
-
76
-        return call_user_func_array($function, $dependencies);
77
-    }
78
-
79
-    /**
80
-     * Makes an element or class injecting automatically all the dependencies.
81
-     *
82
-     * @param string $abstract   The class name or container element name to make.
83
-     * @param array  $parameters Specific parameters definition.
84
-     *
85
-     * @throws ContainerException
86
-     * @return object|null
87
-     */
88
-
89
-    public function make(string $abstract, array $parameters = [])
90
-    {
91
-        if (isset($this->collection[$abstract])) {
92
-            return $this->get($abstract);
93
-        }
94
-
95
-        if (isset($this->resolving[$abstract])) {
96
-            return $this->resolving[$abstract]($abstract, $parameters);
97
-        }
98
-
99
-        try {
100
-            return ($this->resolving[$abstract] = $this->construct($abstract))($abstract, $parameters);
101
-        } catch (ReflectionException $e) {
102
-            throw new ContainerException("Fail while attempt to make '$abstract'", 0, $e);
103
-        }
104
-    }
105
-
106
-    /**
107
-     * Construct a class and all the dependencies using the reflection library of PHP.
108
-     *
109
-     * @param string $abstract The class name or container element name to make.
110
-     *
111
-     * @throws ReflectionException
112
-     * @return Closure
113
-     */
114
-
115
-    protected function construct(string $abstract) : Closure
116
-    {
117
-        $inspector = new ReflectionClass($abstract);
118
-
119
-        if (($constructor = $inspector->getConstructor()) && ($dependencies = $constructor->getParameters())) {
120
-            return function (string $abstract, array $parameters) use ($inspector, $dependencies) {
121
-                return $inspector->newInstanceArgs(
122
-                    $this->process($abstract, $parameters, $dependencies)
123
-                );
124
-            };
125
-        }
126
-
127
-        return function (string $abstract) {
128
-            return new $abstract;
129
-        };
130
-    }
131
-
132
-    /**
133
-     * Process all dependencies
134
-     *
135
-     * @param string $abstract     The class name or container element name to make
136
-     * @param array  $parameters   User defined parameters that must be used instead of resolved ones
137
-     * @param array  $dependencies Array of ReflectionParameter
138
-     *
139
-     * @throws ContainerException When a dependency cannot be solved.
140
-     * @return array
141
-     */
142
-
143
-    protected function process(string $abstract, array $parameters, array $dependencies) : array
144
-    {
145
-        foreach ($dependencies as &$dependency) {
146
-            if (isset($parameters[$dependency->name])) {
147
-                   $dependency = $parameters[$dependency->name];
148
-            } else $dependency = $this->resolve($abstract, $dependency);
149
-        }
150
-
151
-        return $dependencies;
152
-    }
153
-
154
-    /**
155
-     * Resolve all the given class reflected dependencies.
156
-     *
157
-     * @param string               $abstract   The class name or container element name to resolve dependencies.
158
-     * @param ReflectionParameter  $dependency The class dependency to be resolved.
159
-     *
160
-     * @throws ContainerException When a dependency cannot be solved.
161
-     * @return Object
162
-     */
163
-
164
-    protected function resolve(string $abstract, ReflectionParameter $dependency)
165
-    {
166
-        $key = $abstract.$dependency->name;
167
-
168
-        if (! isset($this->resolved[$key])) {
169
-            $this->resolved[$key] = $this->generate($abstract, $dependency);
170
-        }
171
-
172
-        return $this->resolved[$key]($this);
173
-    }
174
-
175
-    /**
176
-     * Generate the dependencies callbacks to jump some conditions in every dependency creation.
177
-     *
178
-     * @param string               $abstract   The class name or container element name to resolve dependencies.
179
-     * @param ReflectionParameter  $dependency The class dependency to be resolved.
180
-     *
181
-     * @throws ContainerException When a dependency cannot be solved.
182
-     * @return Closure
183
-     */
184
-
185
-    protected function generate(string $abstract, ReflectionParameter $dependency) : Closure
186
-    {
187
-        if ($class = $dependency->getClass()) {
188
-            $classname = $class->name;
189
-            $key = $abstract.$classname;
190
-
191
-            if (isset($this->dependencies[$key])) {
192
-                return $this->dependencies[$key];
193
-            }
194
-
195
-            return function () use ($classname) {
196
-                return $this->make($classname);
197
-            };
198
-        }
199
-
200
-        try {
201
-            $value = $dependency->getDefaultValue();
202
-
203
-            return function () use ($value) {
204
-                return $value;
205
-            };
206
-        } catch (ReflectionException $e) {
207
-            throw new ContainerException("Cannot resolve '" . $dependency->name . "' of '$abstract'", 0, $e);
208
-        }
209
-    }
210
-
211
-    /**
212
-     * Reset the container, removing all the elements, cache and options.
213
-     *
214
-     * @return self
215
-     */
216
-
217
-    public function flush() : self
218
-    {
219
-        $this->collection = [];
220
-        $this->dependencies = [];
221
-        $this->resolving = [];
222
-        $this->resolved = [];
223
-
224
-        return $this;
225
-    }
226
-
227
-    /**
228
-     * Finds an entry of the container by its identifier and returns it.
229
-     *
230
-     * @param string $abstract Identifier of the entry to look for.
231
-     *
232
-     * @throws NotFoundException  No entry was found for this identifier.
233
-     * @throws ContainerException Error while retrieving the entry.
234
-     *
235
-     * @return mixed Entry.
236
-     */
237
-    public function get($abstract)
238
-    {
239
-        if (! isset($this->collection[$abstract])) {
240
-            throw new NotFoundException("Element '$abstract' not found");
241
-        }
242
-
243
-        if ($this->collection[$abstract] instanceof Closure) {
244
-            try {
245
-                return $this->collection[$abstract]($this);
246
-            } catch (Exception $e) {
247
-                throw new ContainerException("An exception was thrown while attempt to make $abstract", 0, $e);
248
-            }
249
-        }
250
-
251
-        return $this->collection[$abstract];
252
-    }
253
-
254
-    /**
255
-     * Returns true if the container can return an entry for the given identifier.
256
-     * Returns false otherwise.
257
-     *
258
-     * `has($abstract)` returning true does not mean that `get($abstract)` will not throw an exception.
259
-     * It does however mean that `get($abstract)` will not throw a `NotFoundException`.
260
-     *
261
-     * @param string $abstract Identifier of the entry to look for.
262
-     *
263
-     * @return boolean
264
-     */
265
-
266
-    public function has($abstract)
267
-    {
268
-        return isset($this->collection[$abstract]);
269
-    }
270
-
271
-    /**
272
-     * Verify if an element has a singleton instance.
273
-     *
274
-     * @param  string The class name or container element name to resolve dependencies.
275
-     * @return bool
276
-     */
277
-
278
-    public function isSingleton(string $abstract) : bool
279
-    {
280
-        return isset($this->collection[$abstract]) && $this->collection[$abstract] instanceof Closure === false;
281
-    }
282
-
283
-    /**
284
-     * Verify if an element is a instance of something.
285
-     *
286
-     * @param  string The class name or container element name to resolve dependencies.
287
-     * @return bool
288
-     */
289
-    public function isInstance(string $abstract) : bool
290
-    {
291
-        return isset($this->collection[$abstract]) && is_object($this->collection[$abstract]);
292
-    }
293
-
294
-    /**
295
-     * Bind a new element to the container.
296
-     *
297
-     * @param string                $abstract The alias name that will be used to call the element.
298
-     * @param string|closure|object $concrete The element class name, or an closure that makes the element, or the object itself.
299
-     * @param bool                  $shared   Define if the element will be a singleton instance.
300
-     *
301
-     * @return self
302
-     */
303
-
304
-    public function set(string $abstract, $concrete, bool $shared = false) : self
305
-    {
306
-        if (is_object($concrete)) {
307
-            return $this->instance($abstract, $concrete);
308
-        }
309
-
310
-        if ($concrete instanceof Closure === false) {
311
-            $concrete = function (Container $container) use ($concrete) {
312
-                return $container->make($concrete);
313
-            };
314
-        }
315
-
316
-        if ($shared === true) {
317
-               $this->collection[$abstract] = $concrete($this);
318
-        } else $this->collection[$abstract] = $concrete;
319
-
320
-        return $this;
321
-    }
322
-
323
-    /**
324
-     * Bind a new element to the container IF the element name not exists in the container.
325
-     *
326
-     * @param string         $abstract The alias name that will be used to call the element.
327
-     * @param string|closure $concrete The element class name, or an closure that makes the element.
328
-     * @param bool           $shared   Define if the element will be a singleton instance.
329
-     *
330
-     * @return self
331
-     */
332
-
333
-    public function setIf(string $abstract, $concrete, bool $shared = false) : self
334
-    {
335
-        if (! isset($this->collection[$abstract])) {
336
-            $this->set($abstract, $concrete, $shared);
337
-        }
338
-
339
-        return $this;
340
-    }
341
-
342
-    /**
343
-     * Bind an specific instance to a class dependency.
344
-     *
345
-     * @param string         $class          The class full name.
346
-     * @param string         $dependencyName The dependency full name.
347
-     * @param string|closure $dependency     The specific object class name or a classure that makes the element.
348
-     *
349
-     * @return self
350
-     */
351
-
352
-    public function setTo(string $class, string $dependencyName, $dependency) : self
353
-    {
354
-        if ($dependency instanceof Closure === false) {
355
-            if (is_object($dependency)) {
356
-                $dependency = function () use ($dependency) {
357
-                    return $dependency;
358
-                };
359
-            } else {
360
-                $dependency = function () use ($dependency) {
361
-                    return $this->get($dependency);
362
-                };
363
-            }
364
-        }
365
-
366
-        $this->dependencies[$class.$dependencyName] = $dependency;
367
-
368
-        return $this;
369
-    }
370
-
371
-    /**
372
-     * Bind an element that will be construct only one time, and every call for the element,
373
-     * the same instance will be given.
374
-     *
375
-     * @param string         $abstract The alias name that will be used to call the element.
376
-     * @param string|closure $concrete The element class name, or an closure that makes the element.
377
-     *
378
-     * @return self
379
-     */
380
-
381
-    public function singleton(string $abstract, $concrete) : self
382
-    {
383
-        $this->set($abstract, $concrete, true);
384
-
385
-        return $this;
386
-    }
387
-
388
-    /**
389
-     * Bind an object to the container.
390
-     *
391
-     * @param string $abstract The alias name that will be used to call the object.
392
-     * @param object $instance The object that will be inserted.
393
-     *
394
-     * @throws ContainerException When $instance is not an object.
395
-     * @return self
396
-     */
397
-
398
-    public function instance(string $abstract, $instance) : self
399
-    {
400
-        if (! is_object($instance)) {
401
-            throw new ContainerException('Trying to store ' . gettype($type) . ' as object.');
402
-        }
403
-
404
-        $this->collection[$abstract] = $instance;
405
-
406
-        return $this;
407
-    }
408
-
409
-    /**
410
-     * Modify an element with a given function that receive the old element as argument.
411
-     *
412
-     * @param string  $abstract  The alias name that will be used to call the element.
413
-     * @param closure $extension The function that receives the old element and return a new or modified one.
414
-     *
415
-     * @throws NotFoundException  When no element was found with $abstract key.
416
-     * @return self
417
-     */
418
-
419
-    public function extend(string $abstract, closure $extension) : self
420
-    {
421
-        if (! isset($this->collection[$abstract])) {
422
-            throw new NotFoundException($abstract);
423
-        }
424
-
425
-        $object = $this->collection[$abstract];
426
-
427
-        if ($object instanceof Closure) {
428
-            $this->collection[$abstract] = function () use ($object, $extension) {
429
-                return $extension($object($this), $this);
430
-            };
431
-        } else {
432
-            $this->collection[$abstract] = $extension($object, $this);
433
-        }
434
-
435
-        return $this;
436
-    }
437
-
438
-    /**
439
-     * Makes an resolvable element an singleton.
440
-     *
441
-     * @param  string $abstract The alias name that will be used to call the element.
442
-     *
443
-     * @throws NotFoundException  When no element was found with $abstract key.
444
-     * @throws ContainerException When the element on $abstract key is not resolvable.
445
-     *
446
-     * @return self
447
-     */
448
-
449
-    public function share(string $abstract) : self
450
-    {
451
-        if (! isset($this->collection[$abstract])) {
452
-            throw new NotFoundException("Element '$abstract' not found");
453
-        }
454
-
455
-        if (! $this->collection[$abstract] instanceof Closure) {
456
-            throw new ContainerException("'$abstract' must be a resolvable element");
457
-        }
458
-
459
-        $this->collection[$abstract] = $this->collection[$abstract]($this);
460
-
461
-        return $this;
462
-    }
28
+	/**
29
+	 * Holds all resolved or resolvable instances into the container.
30
+	 *
31
+	 * @var array
32
+	 */
33
+
34
+	protected $collection;
35
+
36
+	/**
37
+	 * Class specific defined dependencies.
38
+	 *
39
+	 * @var array
40
+	 */
41
+
42
+	protected $dependencies;
43
+
44
+	/**
45
+	 * Cache of classes inspector and resolver.
46
+	 *
47
+	 * @var array
48
+	 */
49
+
50
+	protected $resolving;
51
+
52
+	/**
53
+	 * Cache of classes dependencies in callbacks ready for resolution.
54
+	 *
55
+	 * @var array
56
+	 */
57
+
58
+	protected $resolved;
59
+
60
+	/**
61
+	 * Call a user function injecting the dependencies.
62
+	 *
63
+	 * @param string|Closure $function   The function or the user function name.
64
+	 * @param array          $parameters The predefined dependencies.
65
+	 *
66
+	 * @return mixed
67
+	 */
68
+
69
+	public function call($function, array $parameters = [])
70
+	{
71
+		$inspector = new ReflectionFunction($function);
72
+
73
+		$dependencies = $inspector->getParameters();
74
+		$dependencies = $this->process('', $parameters, $dependencies);
75
+
76
+		return call_user_func_array($function, $dependencies);
77
+	}
78
+
79
+	/**
80
+	 * Makes an element or class injecting automatically all the dependencies.
81
+	 *
82
+	 * @param string $abstract   The class name or container element name to make.
83
+	 * @param array  $parameters Specific parameters definition.
84
+	 *
85
+	 * @throws ContainerException
86
+	 * @return object|null
87
+	 */
88
+
89
+	public function make(string $abstract, array $parameters = [])
90
+	{
91
+		if (isset($this->collection[$abstract])) {
92
+			return $this->get($abstract);
93
+		}
94
+
95
+		if (isset($this->resolving[$abstract])) {
96
+			return $this->resolving[$abstract]($abstract, $parameters);
97
+		}
98
+
99
+		try {
100
+			return ($this->resolving[$abstract] = $this->construct($abstract))($abstract, $parameters);
101
+		} catch (ReflectionException $e) {
102
+			throw new ContainerException("Fail while attempt to make '$abstract'", 0, $e);
103
+		}
104
+	}
105
+
106
+	/**
107
+	 * Construct a class and all the dependencies using the reflection library of PHP.
108
+	 *
109
+	 * @param string $abstract The class name or container element name to make.
110
+	 *
111
+	 * @throws ReflectionException
112
+	 * @return Closure
113
+	 */
114
+
115
+	protected function construct(string $abstract) : Closure
116
+	{
117
+		$inspector = new ReflectionClass($abstract);
118
+
119
+		if (($constructor = $inspector->getConstructor()) && ($dependencies = $constructor->getParameters())) {
120
+			return function (string $abstract, array $parameters) use ($inspector, $dependencies) {
121
+				return $inspector->newInstanceArgs(
122
+					$this->process($abstract, $parameters, $dependencies)
123
+				);
124
+			};
125
+		}
126
+
127
+		return function (string $abstract) {
128
+			return new $abstract;
129
+		};
130
+	}
131
+
132
+	/**
133
+	 * Process all dependencies
134
+	 *
135
+	 * @param string $abstract     The class name or container element name to make
136
+	 * @param array  $parameters   User defined parameters that must be used instead of resolved ones
137
+	 * @param array  $dependencies Array of ReflectionParameter
138
+	 *
139
+	 * @throws ContainerException When a dependency cannot be solved.
140
+	 * @return array
141
+	 */
142
+
143
+	protected function process(string $abstract, array $parameters, array $dependencies) : array
144
+	{
145
+		foreach ($dependencies as &$dependency) {
146
+			if (isset($parameters[$dependency->name])) {
147
+				   $dependency = $parameters[$dependency->name];
148
+			} else $dependency = $this->resolve($abstract, $dependency);
149
+		}
150
+
151
+		return $dependencies;
152
+	}
153
+
154
+	/**
155
+	 * Resolve all the given class reflected dependencies.
156
+	 *
157
+	 * @param string               $abstract   The class name or container element name to resolve dependencies.
158
+	 * @param ReflectionParameter  $dependency The class dependency to be resolved.
159
+	 *
160
+	 * @throws ContainerException When a dependency cannot be solved.
161
+	 * @return Object
162
+	 */
163
+
164
+	protected function resolve(string $abstract, ReflectionParameter $dependency)
165
+	{
166
+		$key = $abstract.$dependency->name;
167
+
168
+		if (! isset($this->resolved[$key])) {
169
+			$this->resolved[$key] = $this->generate($abstract, $dependency);
170
+		}
171
+
172
+		return $this->resolved[$key]($this);
173
+	}
174
+
175
+	/**
176
+	 * Generate the dependencies callbacks to jump some conditions in every dependency creation.
177
+	 *
178
+	 * @param string               $abstract   The class name or container element name to resolve dependencies.
179
+	 * @param ReflectionParameter  $dependency The class dependency to be resolved.
180
+	 *
181
+	 * @throws ContainerException When a dependency cannot be solved.
182
+	 * @return Closure
183
+	 */
184
+
185
+	protected function generate(string $abstract, ReflectionParameter $dependency) : Closure
186
+	{
187
+		if ($class = $dependency->getClass()) {
188
+			$classname = $class->name;
189
+			$key = $abstract.$classname;
190
+
191
+			if (isset($this->dependencies[$key])) {
192
+				return $this->dependencies[$key];
193
+			}
194
+
195
+			return function () use ($classname) {
196
+				return $this->make($classname);
197
+			};
198
+		}
199
+
200
+		try {
201
+			$value = $dependency->getDefaultValue();
202
+
203
+			return function () use ($value) {
204
+				return $value;
205
+			};
206
+		} catch (ReflectionException $e) {
207
+			throw new ContainerException("Cannot resolve '" . $dependency->name . "' of '$abstract'", 0, $e);
208
+		}
209
+	}
210
+
211
+	/**
212
+	 * Reset the container, removing all the elements, cache and options.
213
+	 *
214
+	 * @return self
215
+	 */
216
+
217
+	public function flush() : self
218
+	{
219
+		$this->collection = [];
220
+		$this->dependencies = [];
221
+		$this->resolving = [];
222
+		$this->resolved = [];
223
+
224
+		return $this;
225
+	}
226
+
227
+	/**
228
+	 * Finds an entry of the container by its identifier and returns it.
229
+	 *
230
+	 * @param string $abstract Identifier of the entry to look for.
231
+	 *
232
+	 * @throws NotFoundException  No entry was found for this identifier.
233
+	 * @throws ContainerException Error while retrieving the entry.
234
+	 *
235
+	 * @return mixed Entry.
236
+	 */
237
+	public function get($abstract)
238
+	{
239
+		if (! isset($this->collection[$abstract])) {
240
+			throw new NotFoundException("Element '$abstract' not found");
241
+		}
242
+
243
+		if ($this->collection[$abstract] instanceof Closure) {
244
+			try {
245
+				return $this->collection[$abstract]($this);
246
+			} catch (Exception $e) {
247
+				throw new ContainerException("An exception was thrown while attempt to make $abstract", 0, $e);
248
+			}
249
+		}
250
+
251
+		return $this->collection[$abstract];
252
+	}
253
+
254
+	/**
255
+	 * Returns true if the container can return an entry for the given identifier.
256
+	 * Returns false otherwise.
257
+	 *
258
+	 * `has($abstract)` returning true does not mean that `get($abstract)` will not throw an exception.
259
+	 * It does however mean that `get($abstract)` will not throw a `NotFoundException`.
260
+	 *
261
+	 * @param string $abstract Identifier of the entry to look for.
262
+	 *
263
+	 * @return boolean
264
+	 */
265
+
266
+	public function has($abstract)
267
+	{
268
+		return isset($this->collection[$abstract]);
269
+	}
270
+
271
+	/**
272
+	 * Verify if an element has a singleton instance.
273
+	 *
274
+	 * @param  string The class name or container element name to resolve dependencies.
275
+	 * @return bool
276
+	 */
277
+
278
+	public function isSingleton(string $abstract) : bool
279
+	{
280
+		return isset($this->collection[$abstract]) && $this->collection[$abstract] instanceof Closure === false;
281
+	}
282
+
283
+	/**
284
+	 * Verify if an element is a instance of something.
285
+	 *
286
+	 * @param  string The class name or container element name to resolve dependencies.
287
+	 * @return bool
288
+	 */
289
+	public function isInstance(string $abstract) : bool
290
+	{
291
+		return isset($this->collection[$abstract]) && is_object($this->collection[$abstract]);
292
+	}
293
+
294
+	/**
295
+	 * Bind a new element to the container.
296
+	 *
297
+	 * @param string                $abstract The alias name that will be used to call the element.
298
+	 * @param string|closure|object $concrete The element class name, or an closure that makes the element, or the object itself.
299
+	 * @param bool                  $shared   Define if the element will be a singleton instance.
300
+	 *
301
+	 * @return self
302
+	 */
303
+
304
+	public function set(string $abstract, $concrete, bool $shared = false) : self
305
+	{
306
+		if (is_object($concrete)) {
307
+			return $this->instance($abstract, $concrete);
308
+		}
309
+
310
+		if ($concrete instanceof Closure === false) {
311
+			$concrete = function (Container $container) use ($concrete) {
312
+				return $container->make($concrete);
313
+			};
314
+		}
315
+
316
+		if ($shared === true) {
317
+			   $this->collection[$abstract] = $concrete($this);
318
+		} else $this->collection[$abstract] = $concrete;
319
+
320
+		return $this;
321
+	}
322
+
323
+	/**
324
+	 * Bind a new element to the container IF the element name not exists in the container.
325
+	 *
326
+	 * @param string         $abstract The alias name that will be used to call the element.
327
+	 * @param string|closure $concrete The element class name, or an closure that makes the element.
328
+	 * @param bool           $shared   Define if the element will be a singleton instance.
329
+	 *
330
+	 * @return self
331
+	 */
332
+
333
+	public function setIf(string $abstract, $concrete, bool $shared = false) : self
334
+	{
335
+		if (! isset($this->collection[$abstract])) {
336
+			$this->set($abstract, $concrete, $shared);
337
+		}
338
+
339
+		return $this;
340
+	}
341
+
342
+	/**
343
+	 * Bind an specific instance to a class dependency.
344
+	 *
345
+	 * @param string         $class          The class full name.
346
+	 * @param string         $dependencyName The dependency full name.
347
+	 * @param string|closure $dependency     The specific object class name or a classure that makes the element.
348
+	 *
349
+	 * @return self
350
+	 */
351
+
352
+	public function setTo(string $class, string $dependencyName, $dependency) : self
353
+	{
354
+		if ($dependency instanceof Closure === false) {
355
+			if (is_object($dependency)) {
356
+				$dependency = function () use ($dependency) {
357
+					return $dependency;
358
+				};
359
+			} else {
360
+				$dependency = function () use ($dependency) {
361
+					return $this->get($dependency);
362
+				};
363
+			}
364
+		}
365
+
366
+		$this->dependencies[$class.$dependencyName] = $dependency;
367
+
368
+		return $this;
369
+	}
370
+
371
+	/**
372
+	 * Bind an element that will be construct only one time, and every call for the element,
373
+	 * the same instance will be given.
374
+	 *
375
+	 * @param string         $abstract The alias name that will be used to call the element.
376
+	 * @param string|closure $concrete The element class name, or an closure that makes the element.
377
+	 *
378
+	 * @return self
379
+	 */
380
+
381
+	public function singleton(string $abstract, $concrete) : self
382
+	{
383
+		$this->set($abstract, $concrete, true);
384
+
385
+		return $this;
386
+	}
387
+
388
+	/**
389
+	 * Bind an object to the container.
390
+	 *
391
+	 * @param string $abstract The alias name that will be used to call the object.
392
+	 * @param object $instance The object that will be inserted.
393
+	 *
394
+	 * @throws ContainerException When $instance is not an object.
395
+	 * @return self
396
+	 */
397
+
398
+	public function instance(string $abstract, $instance) : self
399
+	{
400
+		if (! is_object($instance)) {
401
+			throw new ContainerException('Trying to store ' . gettype($type) . ' as object.');
402
+		}
403
+
404
+		$this->collection[$abstract] = $instance;
405
+
406
+		return $this;
407
+	}
408
+
409
+	/**
410
+	 * Modify an element with a given function that receive the old element as argument.
411
+	 *
412
+	 * @param string  $abstract  The alias name that will be used to call the element.
413
+	 * @param closure $extension The function that receives the old element and return a new or modified one.
414
+	 *
415
+	 * @throws NotFoundException  When no element was found with $abstract key.
416
+	 * @return self
417
+	 */
418
+
419
+	public function extend(string $abstract, closure $extension) : self
420
+	{
421
+		if (! isset($this->collection[$abstract])) {
422
+			throw new NotFoundException($abstract);
423
+		}
424
+
425
+		$object = $this->collection[$abstract];
426
+
427
+		if ($object instanceof Closure) {
428
+			$this->collection[$abstract] = function () use ($object, $extension) {
429
+				return $extension($object($this), $this);
430
+			};
431
+		} else {
432
+			$this->collection[$abstract] = $extension($object, $this);
433
+		}
434
+
435
+		return $this;
436
+	}
437
+
438
+	/**
439
+	 * Makes an resolvable element an singleton.
440
+	 *
441
+	 * @param  string $abstract The alias name that will be used to call the element.
442
+	 *
443
+	 * @throws NotFoundException  When no element was found with $abstract key.
444
+	 * @throws ContainerException When the element on $abstract key is not resolvable.
445
+	 *
446
+	 * @return self
447
+	 */
448
+
449
+	public function share(string $abstract) : self
450
+	{
451
+		if (! isset($this->collection[$abstract])) {
452
+			throw new NotFoundException("Element '$abstract' not found");
453
+		}
454
+
455
+		if (! $this->collection[$abstract] instanceof Closure) {
456
+			throw new ContainerException("'$abstract' must be a resolvable element");
457
+		}
458
+
459
+		$this->collection[$abstract] = $this->collection[$abstract]($this);
460
+
461
+		return $this;
462
+	}
463 463
 
464 464
 }
Please login to merge, or discard this patch.
Spacing   +17 added lines, -17 removed lines patch added patch discarded remove patch
@@ -117,14 +117,14 @@  discard block
 block discarded – undo
117 117
         $inspector = new ReflectionClass($abstract);
118 118
 
119 119
         if (($constructor = $inspector->getConstructor()) && ($dependencies = $constructor->getParameters())) {
120
-            return function (string $abstract, array $parameters) use ($inspector, $dependencies) {
120
+            return function(string $abstract, array $parameters) use ($inspector, $dependencies) {
121 121
                 return $inspector->newInstanceArgs(
122 122
                     $this->process($abstract, $parameters, $dependencies)
123 123
                 );
124 124
             };
125 125
         }
126 126
 
127
-        return function (string $abstract) {
127
+        return function(string $abstract) {
128 128
             return new $abstract;
129 129
         };
130 130
     }
@@ -165,7 +165,7 @@  discard block
 block discarded – undo
165 165
     {
166 166
         $key = $abstract.$dependency->name;
167 167
 
168
-        if (! isset($this->resolved[$key])) {
168
+        if (!isset($this->resolved[$key])) {
169 169
             $this->resolved[$key] = $this->generate($abstract, $dependency);
170 170
         }
171 171
 
@@ -192,7 +192,7 @@  discard block
 block discarded – undo
192 192
                 return $this->dependencies[$key];
193 193
             }
194 194
 
195
-            return function () use ($classname) {
195
+            return function() use ($classname) {
196 196
                 return $this->make($classname);
197 197
             };
198 198
         }
@@ -200,11 +200,11 @@  discard block
 block discarded – undo
200 200
         try {
201 201
             $value = $dependency->getDefaultValue();
202 202
 
203
-            return function () use ($value) {
203
+            return function() use ($value) {
204 204
                 return $value;
205 205
             };
206 206
         } catch (ReflectionException $e) {
207
-            throw new ContainerException("Cannot resolve '" . $dependency->name . "' of '$abstract'", 0, $e);
207
+            throw new ContainerException("Cannot resolve '".$dependency->name."' of '$abstract'", 0, $e);
208 208
         }
209 209
     }
210 210
 
@@ -236,7 +236,7 @@  discard block
 block discarded – undo
236 236
      */
237 237
     public function get($abstract)
238 238
     {
239
-        if (! isset($this->collection[$abstract])) {
239
+        if (!isset($this->collection[$abstract])) {
240 240
             throw new NotFoundException("Element '$abstract' not found");
241 241
         }
242 242
 
@@ -308,7 +308,7 @@  discard block
 block discarded – undo
308 308
         }
309 309
 
310 310
         if ($concrete instanceof Closure === false) {
311
-            $concrete = function (Container $container) use ($concrete) {
311
+            $concrete = function(Container $container) use ($concrete) {
312 312
                 return $container->make($concrete);
313 313
             };
314 314
         }
@@ -332,7 +332,7 @@  discard block
 block discarded – undo
332 332
 
333 333
     public function setIf(string $abstract, $concrete, bool $shared = false) : self
334 334
     {
335
-        if (! isset($this->collection[$abstract])) {
335
+        if (!isset($this->collection[$abstract])) {
336 336
             $this->set($abstract, $concrete, $shared);
337 337
         }
338 338
 
@@ -353,11 +353,11 @@  discard block
 block discarded – undo
353 353
     {
354 354
         if ($dependency instanceof Closure === false) {
355 355
             if (is_object($dependency)) {
356
-                $dependency = function () use ($dependency) {
356
+                $dependency = function() use ($dependency) {
357 357
                     return $dependency;
358 358
                 };
359 359
             } else {
360
-                $dependency = function () use ($dependency) {
360
+                $dependency = function() use ($dependency) {
361 361
                     return $this->get($dependency);
362 362
                 };
363 363
             }
@@ -397,8 +397,8 @@  discard block
 block discarded – undo
397 397
 
398 398
     public function instance(string $abstract, $instance) : self
399 399
     {
400
-        if (! is_object($instance)) {
401
-            throw new ContainerException('Trying to store ' . gettype($type) . ' as object.');
400
+        if (!is_object($instance)) {
401
+            throw new ContainerException('Trying to store '.gettype($type).' as object.');
402 402
         }
403 403
 
404 404
         $this->collection[$abstract] = $instance;
@@ -418,14 +418,14 @@  discard block
 block discarded – undo
418 418
 
419 419
     public function extend(string $abstract, closure $extension) : self
420 420
     {
421
-        if (! isset($this->collection[$abstract])) {
421
+        if (!isset($this->collection[$abstract])) {
422 422
             throw new NotFoundException($abstract);
423 423
         }
424 424
 
425 425
         $object = $this->collection[$abstract];
426 426
 
427 427
         if ($object instanceof Closure) {
428
-            $this->collection[$abstract] = function () use ($object, $extension) {
428
+            $this->collection[$abstract] = function() use ($object, $extension) {
429 429
                 return $extension($object($this), $this);
430 430
             };
431 431
         } else {
@@ -448,11 +448,11 @@  discard block
 block discarded – undo
448 448
 
449 449
     public function share(string $abstract) : self
450 450
     {
451
-        if (! isset($this->collection[$abstract])) {
451
+        if (!isset($this->collection[$abstract])) {
452 452
             throw new NotFoundException("Element '$abstract' not found");
453 453
         }
454 454
 
455
-        if (! $this->collection[$abstract] instanceof Closure) {
455
+        if (!$this->collection[$abstract] instanceof Closure) {
456 456
             throw new ContainerException("'$abstract' must be a resolvable element");
457 457
         }
458 458
 
Please login to merge, or discard this patch.