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