Container   F
last analyzed

Complexity

Total Complexity 91

Size/Duplication

Total Lines 853
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 164
c 1
b 0
f 0
dl 0
loc 853
rs 2
wmc 91

47 Methods

Rating   Name   Duplication   Size   Complexity  
A keys() 0 3 1
A get() 0 10 3
A offsetExists() 0 3 1
A set() 0 9 2
A setInstance() 0 3 1
A getSingletonInstance() 0 3 2
A factory() 0 4 1
A resolveObject() 0 7 2
A offsetGet() 0 3 1
A flush() 0 6 1
A getServices() 0 9 2
A getLastParameterOverride() 0 3 2
A getInstance() 0 7 2
A getClosure() 0 8 2
A getBindings() 0 3 1
A resolved() 0 7 3
A getResolveNonClass() 0 13 4
A bind() 0 13 3
A getHasCallbacks() 0 7 2
A getAlias() 0 7 2
A getResolveClass() 0 10 3
A dropInstances() 0 3 1
A singleton() 0 3 1
A getParameterOverride() 0 3 1
A __get() 0 3 1
A instance() 0 13 2
A buildNotInstantiable() 0 11 2
A getHasParameters() 0 3 1
A has() 0 3 1
A extend() 0 13 3
A destroyBinding() 0 4 2
A isSingleton() 0 5 3
A reHas() 0 6 2
A singletonResolved() 0 3 1
A offsetUnset() 0 3 1
A alias() 0 7 2
A make() 0 3 1
A isAlias() 0 3 1
A build() 0 29 4
A remove() 0 3 1
A offsetSet() 0 3 1
A bound() 0 5 3
A __set() 0 3 1
A getValue() 0 7 2
A resolve() 0 31 6
A isBuildable() 0 3 2
A getDependencies() 0 17 4

How to fix   Complexity   

Complex Class

Complex classes like Container often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Container, and based on these observations, apply Extract Interface, too.

1
<?php 
2
3
/**
4
 * Lenevor Framework
5
 *
6
 * LICENSE
7
 *
8
 * This source file is subject to the new BSD license that is bundled
9
 * with this package in the file license.md.
10
 * It is also available through the world-wide-web at this URL:
11
 * https://lenevor.com/license
12
 * If you did not receive a copy of the license and are unable to
13
 * obtain it through the world-wide-web, please send an email
14
 * to [email protected] so we can send you a copy immediately.
15
 *
16
 * @package     Lenevor
17
 * @subpackage  Base
18
 * @link        https://lenevor.com
19
 * @copyright   Copyright (c) 2019 - 2021 Alexander Campo <[email protected]>
20
 * @license     https://opensource.org/licenses/BSD-3-Clause New BSD license or see https://lenevor.com/license or see /license.md
21
 */
22
23
namespace Syscodes\Container;
24
25
use Closure;
26
use ArrayAccess;
27
use ReflectionClass;
28
use ReflectionParameter;
29
use Syscodes\Contracts\Container\NotFoundException;
30
use Syscodes\Container\Exceptions\ContainerException;
31
use Syscodes\Contracts\Container\BindingResolutionException;
32
use Syscodes\Contracts\Container\ExpectedInvokableException;
33
use Syscodes\Container\Exceptions\UnknownIdentifierException;
34
use Syscodes\Contracts\Container\Container as ContainerContract;
35
36
/**
37
 * Class responsible of registering the bindings, instances and 
38
 * dependencies of classes when are contained for to be executes 
39
 * in the services providers.
40
 * 
41
 * @author Alexander Campo <[email protected]>
42
 */
43
class Container implements ArrayAccess, ContainerContract
44
{
45
    /**
46
     * The current globally available container.
47
     * 
48
     * @var string $instance
49
     */
50
    protected static $instance;
51
52
    /**
53
     * The parameter override stack.
54
     *
55
     * @var array $across
56
     */
57
    protected $across = [];
58
59
    /**
60
     * Array of aliased.
61
     * 
62
     * @var array $aliases
63
     */
64
    protected $aliases = [];
65
66
    /**
67
     * Array registry of container bindings.
68
     * 
69
     * @var array $bindings
70
     */
71
    protected $bindings = [];
72
    
73
    /**
74
     * The stack of concretions currently being built.
75
     *
76
     * @var array $buildStack
77
     */
78
    protected $buildStack = [];
79
80
    /**
81
     * All of the registered callbacks.
82
     * 
83
     * @var array $hasCallbacks
84
     */
85
    protected $hasCallbacks = [];
86
87
    /**
88
     * The container's singleton instances.
89
     * 
90
     * @var array $instances
91
     */
92
    protected $instances = [];
93
94
    /**
95
     * An array of the types that have been resolved.
96
     * 
97
     * @var array $resolved
98
     */
99
    protected $resolved = [];
100
101
    /**
102
     * The extender closures for services.
103
     * 
104
     * @var array $services
105
     */
106
    protected $services = [];
107
108
    /**
109
     * Set the globally available instance of the container.
110
     *
111
     * @return static
112
     */
113
    public static function getInstance()
114
    {
115
        if (is_null(static::$instance)) {
0 ignored issues
show
introduced by
The condition is_null(static::instance) is always false.
Loading history...
116
            static::$instance = new static;
117
        }
118
119
        return static::$instance;
0 ignored issues
show
Bug Best Practice introduced by
The expression return static::instance returns the type string which is incompatible with the documented return type Syscodes\Container\Container.
Loading history...
120
    }
121
122
    /**
123
     * Set the shared instance of the container.
124
     *
125
     * @param  \Syscodes\Contracts\Container\Container|null  $container
126
     * 
127
     * @return \Syscodes\Contracts\Container\Container|static
128
     */
129
    public static function setInstance(ContainerContract $container = null)
130
    {
131
        return static::$instance = $container;
0 ignored issues
show
Documentation Bug introduced by
It seems like $container can also be of type Syscodes\Contracts\Container\Container. However, the property $instance is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
132
    }
133
134
    /**
135
     * Alias a type to a diferent name.
136
     * 
137
     * @param  string  $id
138
     * @param  string  $alias
139
     * 
140
     * @return void
141
     * 
142
     * @throws \Syscodes\Container\Exceptions\ContainerException
143
     */
144
    public function alias($id, string $alias)
145
    {
146
        if ($alias === $id) {
147
            throw new ContainerException("[ {$id} ] is aliased to itself");
148
        }
149
150
        $this->aliases[$alias] = $id;
151
    }
152
153
    /**
154
     * Register a binding with container.
155
     * 
156
     * @param  string  $id
157
     * @param  \Closure|string|null  $value
158
     * @param  bool  $singleton
159
     * 
160
     * @return void
161
     */
162
    public function bind($id, $value = null, bool $singleton = false)
163
    { 
164
        $this->dropInstances($id);
165
166
        if (is_null($value)) {
167
            $value = $id;
168
        }
169
170
        if ( ! $value instanceof Closure) {
171
            $value = $this->getClosure($id, $value);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type null; however, parameter $value of Syscodes\Container\Container::getClosure() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

171
            $value = $this->getClosure($id, /** @scrutinizer ignore-type */ $value);
Loading history...
172
        }
173
174
        $this->bindings[$id] = compact('value', 'singleton');
175
    }
176
177
    /**
178
     * Get the closure to be used when building a type.
179
     * 
180
     * @param  string  $id
181
     * @param  string  $value
182
     * 
183
     * @return \Closure
184
     */
185
    protected function getClosure($id, string $value)
186
    {
187
        return function ($container, $parameters = []) use ($id, $value) {
188
            if ($id == $value) {
189
                return $container->build($value);
190
            }
191
                       
192
            return $container->make($value, $parameters);
193
        };
194
195
    }
196
197
    /**
198
     * Instantiate a class instance of the given type.
199
     * 
200
     * @param  string  $class
201
     * 
202
     * @return mixed
203
     * 
204
     * @throws \Syscodes\Contracts\Container\BindingResolutionException
205
     */
206
    public function build($class)
207
    {
208
        if ($class instanceof Closure) {
0 ignored issues
show
introduced by
$class is never a sub-type of Closure.
Loading history...
209
            return $class($this, $this->getLastParameterOverride());
210
        }
211
212
        $reflection = new ReflectionClass($class);
213
214
        if ( ! $reflection->isInstantiable()) {
215
            return $this->buildNotInstantiable($class);
216
        }
217
218
        $this->buildStack[] = $class;
219
220
        $constructor = $reflection->getConstructor();
221
222
        if (is_null($constructor)) {
223
            array_pop($this->buildStack);
224
225
            return new $class;
226
        }
227
228
        $dependencies = $constructor->getParameters();
229
230
        $instances = $this->getDependencies($dependencies);
231
232
        array_pop($this->buildStack);
233
        
234
        return $reflection->newInstanceArgs($instances);
235
    }
236
237
    /**
238
     * Throw an exception that the class is not instantiable.
239
     *
240
     * @param  string  $class
241
     * 
242
     * @return void
243
     *
244
     * @throws \Syscodes\Contracts\Container\BindingResolutionException
245
     */
246
    protected function buildNotInstantiable(string $class)
247
    {
248
        if ( ! empty($this->buildStack)) {
249
           $reset   = implode(', ', $this->buildStack);
250
251
           $message = "Target [ {$class} ] is not instantiable while building [ {$reset} ]."; 
252
        } else {
253
            $message = "Target [ {$class} ] is not instantiable.";
254
        }
255
256
        throw new BindingResolutionException($message);
257
    }
258
259
    /**
260
     * Resolve all of the dependencies from the ReflectionParameters.
261
     * 
262
     * @param  array  $dependencies
263
     * 
264
     * @return array
265
     */
266
    protected function getDependencies(array $dependencies) 
267
    {
268
        $param = [];
269
270
        foreach ($dependencies as $dependency) {
271
            if ($this->getHasParameters($dependency)) {
272
                $param[] = $this->getParameterOverride($dependency);
273
274
                continue;
275
            }
276
277
            $param[] = is_null($dependency->getClass()) 
278
                       ? $this->getResolveNonClass($dependency) 
279
                       : $this->getResolveClass($dependency);
280
        }
281
282
        return $param;
283
    }
284
285
    /**
286
     * Determine if the given dependency has a parameter override.
287
     *
288
     * @param  \ReflectionParameter  $dependency
289
     * 
290
     * @return bool
291
     */
292
    protected function getHasParameters($dependency)
293
    {
294
        return array_key_exists($dependency->name, $this->getLastParameterOverride());
295
    }
296
297
    /**
298
     * Get the last parameter override.
299
     *
300
     * @return array
301
     */
302
    protected function getLastParameterOverride()
303
    {
304
        return count($this->across) ? end($this->across) : [];
305
    }
306
307
    /**
308
     * Get a parameter override for a dependency.
309
     *
310
     * @param  \ReflectionParameter  $dependency
311
     * 
312
     * @return mixed
313
     */
314
    protected function getParameterOverride($dependency)
315
    {
316
        return $this->getLastParameterOverride()[$dependency->name];
317
    }
318
319
    /**
320
     * Resolve a class based dependency from the container.
321
     *
322
     * @param  \ReflectionParameter  $parameter
323
     * 
324
     * @return mixed
325
     *
326
     * @throws \Syscodes\Container\Exceptions\BindingResolutionException
327
     */
328
    protected function getResolveClass(ReflectionParameter $parameter)
329
    {
330
        try {
331
            return $this->make($parameter->getClass()->name);
332
        } catch (BindingResolutionException $e) {
333
            if ($parameter->isOptional()) {
334
                return $parameter->getDefaultValue();
335
            }
336
337
            throw $e;
338
        }
339
    }
340
341
    /**
342
     * Resolve a non-class hinted dependency.
343
     *
344
     * @param  \ReflectionParameter  $parameter
345
     * 
346
     * @return mixed
347
     *
348
     * @throws \Syscodes\Container\Exceptions\BindingResolutionException
349
     */
350
    protected function getResolveNonClass(ReflectionParameter $parameter)
351
    {
352
        if ( ! is_null($class = $parameter->name)) {
0 ignored issues
show
introduced by
The condition is_null($class = $parameter->name) is always false.
Loading history...
353
            return $class instanceof Closure ? $class($this) : $class;
0 ignored issues
show
introduced by
$class is never a sub-type of Closure.
Loading history...
354
        }
355
356
        if ($parameter->isDefaultValueAvailable()) {
357
            return $parameter->getDefaultValue();
358
        }
359
360
        $message = "Unresolvable dependency resolving [ {$parameter} ] in class [ {$parameter->getDeclaringClass()->getName()} ]";
361
362
        throw new BindingResolutionException($message);
363
    }
364
365
    /**
366
     * Extender an id type in the container.
367
     *
368
     * @param  string  $id
369
     * @param  \Closure  $closure
370
     * 
371
     * @return void
372
     */
373
    public function extend($id, Closure $closure) 
374
    {
375
        $id = $this->getAlias($id);
376
377
        if (isset($this->instances[$id])) {
378
            $this->instances[$id] = $closure($this->instances[$id], $this);
379
380
            $this->reHas($id);
381
        } else {
382
            $this->services[$id][] = $closure;
383
            
384
            if ($this->resolved($id)) {
385
                $this->reHas($id);
386
            }
387
        }
388
    }
389
390
    /**
391
     * Remove all id traces of the specified binding.
392
     * 
393
     * @param  string  $id
394
     * 
395
     * @return void
396
     */
397
    protected function destroyBinding($id)
398
    {
399
        if ($this->has($id)) {
400
            unset($this->bindings[$id], $this->instances[$id], $this->resolved[$id]);
401
        }
402
    }
403
404
    /**
405
     * Drop all of the stale instances and aliases.
406
     *
407
     * @param  string  $id
408
     * 
409
     * @return void
410
     */
411
    protected function dropInstances($id)
412
    {
413
        unset($this->instances[$id], $this->aliases[$id]);
414
    }
415
416
    /**
417
     * Marks a callable as being a factory service.
418
     * 
419
     * @param  string  $id
420
     * 
421
     * @return void
422
     */
423
    public function factory($id)
424
    {
425
        return function () use ($id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression return function(...) { /* ... */ } returns the type callable which is incompatible with the documented return type void.
Loading history...
426
            return $this->make($id);
427
        };
428
    }
429
430
    /**
431
     * Flush the container of all bindings and resolved instances.
432
     * 
433
     * @return void
434
     */
435
    public function flush()
436
    {
437
        $this->aliases   = [];
438
        $this->resolved  = [];
439
        $this->bindings  = [];
440
        $this->instances = [];
441
    }
442
443
    /**
444
     * Get the alias for an id if available.
445
     * 
446
     * @param  string  $id
447
     * 
448
     * @return string
449
     */
450
    public function getAlias($id)
451
    {
452
        if ( ! isset($this->aliases[$id])) {
453
            return $id;
454
        }
455
456
        return $this->getAlias($this->aliases[$id]);
457
    }
458
459
    /**
460
     * Return and array containing all bindings.
461
     * 
462
     * @return array
463
     */
464
    public function getBindings()
465
    {
466
        return $this->bindings;
467
    }
468
469
    /**
470
     * Get the class type for a given id.
471
     * 
472
     * @param  string  $id
473
     * 
474
     * @return mixed
475
     */
476
    protected function getValue($id)
477
    {
478
        if (isset($this->bindings[$id])) {
479
            return $this->bindings[$id]['value'];
480
        }
481
482
        return $id;
483
    }
484
485
    /**
486
     * Get the has callbacks for a given type.
487
     * 
488
     * @param  string  $id
489
     * 
490
     * @return array
491
     */
492
    protected function getHasCallbacks($id)
493
    {
494
        if (isset($this->hasCallbacks[$id])) {
495
            return $this->hasCallbacks[$id];
496
        }
497
498
        return [];
499
    }
500
501
    /**
502
     * Get the services callbacks for a given type.
503
     * 
504
     * @param  string  $id
505
     * 
506
     * @return array
507
     */
508
    protected function getServices($id)
509
    {
510
        $id = $this->getAlias($id);
511
512
        if (isset($this->services[$id])) {
513
            return $this->services[$id];
514
        }
515
516
        return [];
517
    }
518
519
    /**
520
     * Get a given instance through of an object singleton.
521
     * 
522
     * @param  string  $id
523
     * 
524
     * @return mixed
525
     */
526
    protected function getSingletonInstance($id)
527
    {
528
        return $this->singletonResolved($id) ? $this->instances[$id] : null;
529
    }
530
531
    /**
532
     * Register an existing instance as singleton in the container.
533
     *
534
     * @param  string  $id
535
     * @param  mixed  $instance
536
     * 
537
     * @return mixed
538
     */
539
    public function instance($id, $instance) 
540
    {
541
        $bound = $this->bound($id);
542
543
        unset($this->aliases[$id]);
544
545
        $this->instances[$id] = $instance;
546
547
        if ($bound) {
548
            $this->rehas($id);
549
        }
550
551
        return $instance;
552
    }
553
554
    /**
555
     * Determine if a given string is an alias.
556
     * 
557
     * @param  string  $name
558
     * 
559
     * @return bool
560
     */
561
    public function isAlias($name)
562
    {
563
        return isset($this->aliases[$name]);
564
    }
565
566
    /**
567
     * Determine if the given id is buildable.
568
     * 
569
     * @param  string  $class
570
     * @param  string  $id
571
     * 
572
     * @return string
573
     */
574
    protected function isBuildable($class, $id)
575
    {
576
        return $class === $id || $class instanceof Closure;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $class === $id || $class instanceof Closure returns the type boolean which is incompatible with the documented return type string.
Loading history...
577
    }
578
579
    /**
580
     * Determine if a given type is singleton.
581
     * 
582
     * @param  string  $id
583
     * 
584
     * @return bool
585
     */
586
    protected function isSingleton($id)
587
    {
588
        return isset($this->instances[$id]) ||
589
               (isset($this->bindings[$id]['singleton']) &&
590
               $this->bindings[$id]['singleton'] === true);
591
    }
592
593
    /**
594
     * Return all defined value binding.
595
     * 
596
     * @return array
597
     */
598
    public function keys()
599
    {
600
        return array_keys($this->bindings);
601
    }
602
603
    /**
604
     * Resolve the given type from the container.
605
     * 
606
     * @param  string  $id
607
     * @param  array  $parameters
608
     * 
609
     * @return object
610
     */
611
    public function make($id, array $parameters = []) 
612
    {
613
        return $this->resolve($id, $parameters);
614
    }
615
616
    /**
617
     * Activate the  callbacks for the given id type.
618
     * 
619
     * @param  string  $id
620
     * 
621
     * @return void
622
     */
623
    protected function reHas($id)
624
    {
625
        $instance = $this->make($id);
626
627
        foreach ($this->getHasCallbacks($id) as $callback) {
628
            call_user_func($callback, $this, $instance);
629
        }
630
    }
631
    
632
    /**
633
     * Remove all id traces of the specified binding.
634
     * 
635
     * @param  string  $id
636
     * 
637
     * @return void
638
     */
639
    public function remove($id)
640
    {
641
        $this->destroyBinding($id);
642
    }
643
644
    /**
645
     * Resolve the given type from the container.
646
     * 
647
     * @param  string  $id
648
     * @param  array  $parameters
649
     * 
650
     * @return mixed
651
     */
652
    protected function resolve($id, array $parameters = []) 
653
    {
654
        $id = $this->getAlias($id);
655
656
        if (isset($this->instances[$id])) {
657
            return $this->instances[$id];
658
        }
659
660
        $this->across[] = $parameters;
661
        
662
        $value = $this->getValue($id);
663
664
        if ($this->isSingleton($id) && $this->singletonResolved($id)) {
665
            return $this->getSingletonInstance($id);
666
        }
667
668
        if ($this->isBuildable($value, $id)) {
669
            $object = $this->build($value);
670
        } else {
671
            $object = $this->make($value);
672
        }
673
674
        foreach ($this->getServices($id) as $services) {
675
            $object = $services($object, $this);
676
        }
677
678
        $this->resolved[$id] = true;
679
680
        array_pop($this->across);
681
682
       return $this->resolveObject($id, $object);
683
    }
684
685
    /**
686
     * Determine if the given id type has been resolved.
687
     *
688
     * @param  string  $id
689
     * 
690
     * @return bool
691
     */
692
    public function resolved($id)
693
    {
694
        if ($this->isAlias($id)) {
695
            $id = $this->getAlias($id);
696
        }
697
        
698
        return isset($this->resolved[$id]) || isset($this->instances[$id]);
699
    }
700
701
    /**
702
     * Register the identifier given for to be instanced to an object already built.
703
     * 
704
     * @param  string  $id
705
     * @param  string  $object
706
     * 
707
     * @return mixed
708
     */
709
    protected function resolveObject($id, $object)
710
    {
711
        if ($this->isSingleton($id)) {
712
            $this->instances[$id] = $object;
713
        }
714
715
        return $object;
716
    }
717
718
    /**
719
     * Set the binding with given key / value.
720
     * 
721
     * @param  string  $id
722
     * @param  string  $value
723
     * 
724
     * @return $this
725
     * 
726
     * @throws \Syscodes\Container\Exceptions\ContainerException
727
     */
728
    public function set($id, string $value)
729
    {
730
        if ( ! $this->bound($id)) {
731
            throw new ContainerException($id);
732
        }
733
734
        $this->bindings[$id] = $value;
735
736
        return $this;
737
    }
738
739
    /**
740
     * Register a singleton binding in the container.
741
     * 
742
     * @param  string  $id
743
     * @param  \Closure|string|null  $value
744
     * 
745
     * @return void
746
     */
747
    public function singleton($id, $value = null)
748
    {
749
        $this->bind($id, $value, true);
750
    }
751
752
    /**
753
     * Resolve a singleton binding with key array.
754
     * 
755
     * @param  string  $id
756
     * 
757
     * @return bool
758
     */
759
    public function singletonResolved($id)
760
    {
761
        return array_key_exists($id, $this->instances);
762
    }
763
764
    /*
765
    |----------------------------------------------------------------
766
    | ContainerInterface Methods
767
    |---------------------------------------------------------------- 
768
    */
769
770
    /**
771
     * Gets a parameter or an object.
772
     * 
773
     * @param  string  $id
774
     * 
775
     * @return mixed
776
     * 
777
     * @throws \Syscodes\Container\Exceptions\UnknownIdentifierException
778
     */
779
    public function get($id)
780
    {
781
        try {
782
            return $this->resolve($id);
783
        } catch (Exception $e) {
784
            if ( ! $this->has($id)) {
785
                throw new $e;
786
            }   
787
788
            throw new UnknownIdentifierException($id);
789
        }
790
    }
791
792
    /**
793
     * Check if binding with $id exists.
794
     * 
795
     * @param  string  $id
796
     * 
797
     * @return bool
798
     */
799
    public function has($id)
800
    {
801
        return $this->bound($id);
802
    }
803
804
    /**
805
     * Determine if the given id type has been bound.
806
     * 
807
     * @param  string  $id
808
     * 
809
     * @return bool
810
     */
811
    public function bound($id)
812
    {
813
        return isset($this->bindings[$id])  ||
814
               isset($this->instances[$id]) ||
815
               $this->isAlias($id);
816
    }
817
818
    /*
819
    |-----------------------------------------------------------------
820
    | ArrayAccess Methods
821
    |-----------------------------------------------------------------
822
    */
823
824
    /**
825
     * Determine if a given offset exists.
826
     * 
827
     * @param  string  $offset
828
     * 
829
     * @return bool
830
     */
831
    public function offsetExists($offset)
832
    {
833
        return $this->bound($offset);
834
    }
835
836
    /**
837
     * Get the value at a given offset.
838
     * 
839
     * @param  string  $offset
840
     * 
841
     * @return mixed
842
     */
843
    public function offsetGet($offset)
844
    {
845
        return $this->make($offset);
846
    }
847
848
    /**
849
     * Set the value at a given offset.
850
     * 
851
     * @param  string  $offset
852
     * @param  mixed  $value
853
     * 
854
     * @return void
855
     */
856
    public function offsetSet($offset, $value)
857
    {
858
        $this->set($offset, $value);
859
    }
860
861
    /**
862
     * Unset the value at a given offset.
863
     * 
864
     * @param  string  $offset
865
     * 
866
     * @return void
867
     */
868
    public function offsetUnset($offset)
869
    {
870
        $this->remove($offset);
871
    }
872
873
    /**
874
     * Dynamically access container services.
875
     * 
876
     * @param  string  $key
877
     * 
878
     * @return mixed
879
     */
880
    public function __get($key)
881
    {
882
        return $this[$key];
883
    }
884
885
    /**
886
     * Dynamically set container services.
887
     * 
888
     * @param  string  $key
889
     * @param  mixed  $value
890
     * 
891
     * @return mixed
892
     */
893
    public function __set($key, $value)
894
    {
895
        return $this[$key] = $value;
896
    }
897
}