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