LFT
  • Namespace
  • Class
  • Tree

Namespaces

  • Docoflow
    • Contracts
    • Entity
    • Facades
    • Models
    • Traits
  • Docolight
    • Agno
      • Traits
    • Container
    • Http
      • Contracts
    • Rest
      • Handler
      • Http
    • Support
      • Debug
      • Traits
  • Docotory
    • Traits
  • None

Classes

  • Docoflow\Docoflow
  • Docoflow\Entity\Group
  • Docoflow\Entity\Step
  • Docoflow\Entity\Verificator
  • Docoflow\Facades\Action
  • Docoflow\Facades\Activity
  • Docoflow\Facades\Flo
  • Docoflow\Facades\StateActivity
  • Docoflow\Flo
  • Docoflow\Models\Workflow
  • Docoflow\Models\WorkflowAction
  • Docoflow\Models\WorkflowActivity
  • Docoflow\Models\WorkflowGroups
  • Docoflow\Models\WorkflowNotification
  • Docoflow\Models\WorkflowState
  • Docoflow\Models\WorkflowStateActivity
  • Docoflow\Models\WorkflowStep
  • Docoflow\Models\WorkflowVerificator
  • Docolight
  • Docolight\Agno\AgnoModule
  • Docolight\Container\Container
  • Docolight\Http\Headers
  • Docolight\Http\JsonResponse
  • Docolight\Http\MimeResponse
  • Docolight\Http\Response
  • Docolight\Http\ResponseFactory
  • Docolight\Rest\Handler\RestfulErrorHandler
  • Docolight\Rest\Http\RestFulController
  • Docolight\Support\ActiveRecordWrapper
  • Docolight\Support\Arr
  • Docolight\Support\Carbonate
  • Docolight\Support\ClassLoader
  • Docolight\Support\Collection
  • Docolight\Support\CollectionDataProvider
  • Docolight\Support\Debug\Dumper
  • Docolight\Support\Debug\HtmlDumper
  • Docolight\Support\Facade
  • Docolight\Support\Factory
  • Docolight\Support\Fluent
  • Docolight\Support\Html
  • Docolight\Support\IterablePager
  • Docolight\Support\Repository
  • Docolight\Support\Set
  • Docolight\Support\Str
  • Docotory\Factory

Interfaces

  • Docoflow\Contracts\DocoflowContract
  • Docoflow\Contracts\ValidationStatus
  • Docolight\Http\Contracts\Arrayable

Traits

  • Docoflow\Traits\BulkValidator
  • Docoflow\Traits\Entity
  • Docoflow\Traits\HasMutator
  • Docoflow\Traits\Validable
  • Docolight\Agno\Traits\HasAssetsUrl
  • Docolight\Agno\Traits\HasAutoload
  • Docolight\Support\Traits\Macroable
  • Docotory\Traits\HasFactories

Exceptions

  • Docolight\Container\BindingResolutionException
  • Docotory\ResolvingTypeException

Functions

  • array_add
  • array_build
  • array_collapse
  • array_divide
  • array_dot
  • array_except
  • array_first
  • array_flatten
  • array_forget
  • array_get
  • array_has
  • array_last
  • array_only
  • array_pluck
  • array_pull
  • array_replace_value
  • array_set
  • array_sort
  • array_sort_recursive
  • array_where
  • cache
  • camel_case
  • class_basename
  • class_uses_recursive
  • collect
  • container
  • data_get
  • dd
  • def
  • dump
  • e
  • ends_with
  • fluent
  • get
  • head
  • input
  • last
  • object_get
  • preg_replace_sub
  • request
  • response
  • session
  • snake_case
  • starts_with
  • str_contains
  • str_finish
  • str_is
  • str_limit
  • str_random
  • str_replace_array
  • str_slug
  • studly_case
  • title_case
  • trait_uses_recursive
  • transaction
  • trimtolower
  • value
  • with
  1 <?php
  2 
  3 namespace Docolight\Container;
  4 
  5 use Closure;
  6 use ArrayAccess;
  7 use ReflectionClass;
  8 use ReflectionParameter;
  9 use CApplicationComponent;
 10 use InvalidArgumentException;
 11 
 12 /**
 13  * Inversion of control container is a powerful tool for managing class dependencies. Dependency injection is a method of removing hard-coded class dependencies. Instead, the dependencies are injected at run-time, allowing for greater flexibility as dependency implementations may be swapped easily.
 14  *
 15  * ```php
 16  *
 17  * // Instantiate new container
 18  * $container = new Docolight\Container\Container;
 19  *
 20  * // Bind a container
 21  * $container->bind('foo', function () { return new Foo; });
 22  *
 23  * // Resolve type from container:
 24  * $container->make('foo'); // Foo implementation
 25  * ```
 26  *
 27  * Container also has ability to resolve the dependency by itself.
 28  *
 29  * ```php
 30  *
 31  * interface FooContract { public function foo(); }
 32  *
 33  *
 34  * class Foo implements FooContract { public function foo() {} }
 35  *
 36  *
 37  * class FooFactory
 38  * {
 39  *
 40  *      protected $foo = null;
 41  *
 42  *      public function __construct(FooContract $foo)
 43  *      {
 44  *          $this->foo = $foo;
 45  *      }
 46  * }
 47  *
 48  *
 49  * $container = new Docolight\Container\Container;
 50  *
 51  * $container->bind('FooContract', 'Foo');
 52  *
 53  * $fooFactory = $container->make('FooFactory'); // equals with: $fooFactory = new FooFactory(new Foo);
 54  * ```
 55  *
 56  * @author   Krisan Alfa Timur <krisanalfa@docotel.co.id>
 57  *
 58  * @category Libraries
 59  *
 60  * @link     http://php.net/manual/en/class.arrayaccess.php Interface to provide accessing objects as arrays.
 61  */
 62 class Container extends CApplicationComponent implements ArrayAccess
 63 {
 64     /**
 65      * An array of the types that have been resolved.
 66      *
 67      * @var array
 68      */
 69     protected $resolved = array();
 70 
 71     /**
 72      * The container's bindings.
 73      *
 74      * @var array
 75      */
 76     protected $bindings = array();
 77 
 78     /**
 79      * The container's shared instances.
 80      *
 81      * @var array
 82      */
 83     protected $instances = array();
 84 
 85     /**
 86      * The registered type aliases.
 87      *
 88      * @var array
 89      */
 90     protected $aliases = array();
 91 
 92     /**
 93      * All of the registered rebound callbacks.
 94      *
 95      * @var array
 96      */
 97     protected $reboundCallbacks = array();
 98 
 99     /**
100      * All of the registered resolving callbacks.
101      *
102      * @var array
103      */
104     protected $resolvingCallbacks = array();
105 
106     /**
107      * All of the global resolving callbacks.
108      *
109      * @var array
110      */
111     protected $globalResolvingCallbacks = array();
112 
113     /**
114      * Determine if a given string is resolvable.
115      *
116      * @param string $abstract
117      *
118      * @return bool
119      */
120     protected function resolvable($abstract)
121     {
122         return $this->bound($abstract) || $this->isAlias($abstract);
123     }
124 
125     /**
126      * Determine if the given abstract type has been bound.
127      *
128      * @param string $abstract
129      *
130      * @return bool
131      */
132     public function bound($abstract)
133     {
134         return isset($this->bindings[$abstract]) || isset($this->instances[$abstract]);
135     }
136 
137     /**
138      * Determine if the given abstract type has been resolved.
139      *
140      * @param string $abstract
141      *
142      * @return bool
143      */
144     public function resolved($abstract)
145     {
146         return isset($this->resolved[$abstract]) || isset($this->instances[$abstract]);
147     }
148 
149     /**
150      * Determine if a given string is an alias.
151      *
152      * @param string $name
153      *
154      * @return bool
155      */
156     public function isAlias($name)
157     {
158         return isset($this->aliases[$name]);
159     }
160 
161     /**
162      * Register a binding with the container.
163      *
164      * @param string|array         $abstract
165      * @param \Closure|string|null $concrete
166      * @param bool                 $shared
167      */
168     public function bind($abstract, $concrete = null, $shared = false)
169     {
170         // If the given types are actually an array, we will assume an alias is being
171         // defined and will grab this "real" abstract class name and register this
172         // alias with the container so that it can be used as a shortcut for it.
173         if (is_array($abstract)) {
174             list($abstract, $alias) = $this->extractAlias($abstract);
175 
176             $this->alias($abstract, $alias);
177         }
178 
179         // If no concrete type was given, we will simply set the concrete type to the
180         // abstract type. This will allow concrete type to be registered as shared
181         // without being forced to state their classes in both of the parameter.
182         $this->dropStaleInstances($abstract);
183 
184         if (is_null($concrete)) {
185             $concrete = $abstract;
186         }
187 
188         // If the factory is not a Closure, it means it is just a class name which is
189         // is bound into this container to the abstract type and we will just wrap
190         // it up inside a Closure to make things more convenient when extending.
191         if (!$concrete instanceof Closure) {
192             $concrete = $this->getClosure($abstract, $concrete);
193         }
194 
195         $this->bindings[$abstract] = compact('concrete', 'shared');
196 
197         // If the abstract type was already resolved in this container we'll fire the
198         // rebound listener so that any objects which have already gotten resolved
199         // can have their copy of the object updated via the listener callbacks.
200         if ($this->resolved($abstract)) {
201             $this->rebound($abstract);
202         }
203     }
204 
205     /**
206      * Get the Closure to be used when building a type.
207      *
208      * @param string $abstract
209      * @param string $concrete
210      *
211      * @return \Closure
212      */
213     protected function getClosure($abstract, $concrete)
214     {
215         return function ($c, $parameters = array()) use ($abstract, $concrete) {
216             $method = ($abstract == $concrete) ? 'build' : 'make';
217 
218             return $c->$method($concrete, $parameters);
219         };
220     }
221 
222     /**
223      * Register a binding if it hasn't already been registered.
224      *
225      * @param string               $abstract
226      * @param \Closure|string|null $concrete
227      * @param bool                 $shared
228      */
229     public function bindIf($abstract, $concrete = null, $shared = false)
230     {
231         if (!$this->bound($abstract)) {
232             $this->bind($abstract, $concrete, $shared);
233         }
234     }
235 
236     /**
237      * Register a shared binding in the container.
238      *
239      * @param string               $abstract
240      * @param \Closure|string|null $concrete
241      */
242     public function singleton($abstract, $concrete = null)
243     {
244         $this->bind($abstract, $concrete, true);
245     }
246 
247     /**
248      * Wrap a Closure such that it is shared.
249      *
250      * @param \Closure $closure
251      *
252      * @return \Closure
253      */
254     public function share(Closure $closure)
255     {
256         return function ($container) use ($closure) {
257             // We'll simply declare a static variable within the Closures and if it has
258             // not been set we will execute the given Closures to resolve this value
259             // and return it back to these consumers of the method as an instance.
260             static $object;
261 
262             if (is_null($object)) {
263                 $object = $closure($container);
264             }
265 
266             return $object;
267         };
268     }
269 
270     /**
271      * Bind a shared Closure into the container.
272      *
273      * @param string   $abstract
274      * @param \Closure $closure
275      */
276     public function bindShared($abstract, Closure $closure)
277     {
278         $this->bind($abstract, $this->share($closure), true);
279     }
280 
281     /**
282      * "Extend" an abstract type in the container.
283      *
284      * @param string   $abstract
285      * @param \Closure $closure
286      *
287      * @throws \InvalidArgumentException
288      */
289     public function extend($abstract, Closure $closure)
290     {
291         if (!isset($this->bindings[$abstract])) {
292             throw new InvalidArgumentException("Type {$abstract} is not bound.");
293         }
294 
295         if (isset($this->instances[$abstract])) {
296             $this->instances[$abstract] = $closure($this->instances[$abstract], $this);
297 
298             $this->rebound($abstract);
299         } else {
300             $extender = $this->getExtender($abstract, $closure);
301 
302             $this->bind($abstract, $extender, $this->isShared($abstract));
303         }
304     }
305 
306     /**
307      * Get an extender Closure for resolving a type.
308      *
309      * @param string   $abstract
310      * @param \Closure $closure
311      *
312      * @return \Closure
313      */
314     protected function getExtender($abstract, Closure $closure)
315     {
316         // To "extend" a binding, we will grab the old "resolver" Closure and pass it
317         // into a new one. The old resolver will be called first and the result is
318         // handed off to the "new" resolver, along with this container instance.
319         $resolver = $this->bindings[$abstract]['concrete'];
320 
321         return function ($container) use ($resolver, $closure) {
322             return $closure($resolver($container), $container);
323         };
324     }
325 
326     /**
327      * Register an existing instance as shared in the container.
328      *
329      * @param string $abstract
330      * @param mixed  $instance
331      */
332     public function instance($abstract, $instance)
333     {
334         // First, we will extract the alias from the abstract if it is an array so we
335         // are using the correct name when binding the type. If we get an alias it
336         // will be registered with the container so we can resolve it out later.
337         if (is_array($abstract)) {
338             list($abstract, $alias) = $this->extractAlias($abstract);
339 
340             $this->alias($abstract, $alias);
341         }
342 
343         unset($this->aliases[$abstract]);
344 
345         // We'll check to determine if this type has been bound before, and if it has
346         // we will fire the rebound callbacks registered with the container and it
347         // can be updated with consuming classes that have gotten resolved here.
348         $bound = $this->bound($abstract);
349 
350         $this->instances[$abstract] = $instance;
351 
352         if ($bound) {
353             $this->rebound($abstract);
354         }
355     }
356 
357     /**
358      * Alias a type to a shorter name.
359      *
360      * @param string $abstract
361      * @param string $alias
362      */
363     public function alias($abstract, $alias)
364     {
365         $this->aliases[$alias] = $abstract;
366     }
367 
368     /**
369      * Extract the type and alias from a given definition.
370      *
371      * @param array $definition
372      *
373      * @return array
374      */
375     protected function extractAlias(array $definition)
376     {
377         return array(key($definition), current($definition));
378     }
379 
380     /**
381      * Bind a new callback to an abstract's rebind event.
382      *
383      * @param string   $abstract
384      * @param \Closure $callback
385      *
386      * @return mixed
387      */
388     public function rebinding($abstract, Closure $callback)
389     {
390         $this->reboundCallbacks[$abstract][] = $callback;
391 
392         if ($this->bound($abstract)) {
393             return $this->make($abstract);
394         }
395     }
396 
397     /**
398      * Refresh an instance on the given target and method.
399      *
400      * @param string $abstract
401      * @param mixed  $target
402      * @param string $method
403      *
404      * @return mixed
405      */
406     public function refresh($abstract, $target, $method)
407     {
408         return $this->rebinding($abstract, function ($app, $instance) use ($target, $method) {
409             $target->{$method}($instance);
410         });
411     }
412 
413     /**
414      * Fire the "rebound" callbacks for the given abstract type.
415      *
416      * @param string $abstract
417      */
418     protected function rebound($abstract)
419     {
420         $instance = $this->make($abstract);
421 
422         foreach ($this->getReboundCallbacks($abstract) as $callback) {
423             call_user_func($callback, $this, $instance);
424         }
425     }
426 
427     /**
428      * Get the rebound callbacks for a given type.
429      *
430      * @param string $abstract
431      *
432      * @return array
433      */
434     protected function getReboundCallbacks($abstract)
435     {
436         if (isset($this->reboundCallbacks[$abstract])) {
437             return $this->reboundCallbacks[$abstract];
438         }
439 
440         return array();
441     }
442 
443     /**
444      * Resolve the given type from the container.
445      *
446      * @param string $abstract
447      * @param array  $parameters
448      *
449      * @return mixed
450      */
451     public function make($abstract, $parameters = array())
452     {
453         $abstract = $this->getAlias($abstract);
454 
455         // If an instance of the type is currently being managed as a singleton we'll
456         // just return an existing instance instead of instantiating new instances
457         // so the developer can keep using the same objects instance every time.
458         if (isset($this->instances[$abstract])) {
459             return $this->instances[$abstract];
460         }
461 
462         $concrete = $this->getConcrete($abstract);
463 
464         // We're ready to instantiate an instance of the concrete type registered for
465         // the binding. This will instantiate the types, as well as resolve any of
466         // its "nested" dependencies recursively until all have gotten resolved.
467         if ($this->isBuildable($concrete, $abstract)) {
468             $object = $this->build($concrete, $parameters);
469         } else {
470             $object = $this->make($concrete, $parameters);
471         }
472 
473         // If the requested type is registered as a singleton we'll want to cache off
474         // the instances in "memory" so we can return it later without creating an
475         // entirely new instance of an object on each subsequent request for it.
476         if ($this->isShared($abstract)) {
477             $this->instances[$abstract] = $object;
478         }
479 
480         $this->fireResolvingCallbacks($abstract, $object);
481 
482         $this->resolved[$abstract] = true;
483 
484         return $object;
485     }
486 
487     /**
488      * Get the concrete type for a given abstract.
489      *
490      * @param string $abstract
491      *
492      * @return mixed $concrete
493      */
494     protected function getConcrete($abstract)
495     {
496         // If we don't have a registered resolver or concrete for the type, we'll just
497         // assume each type is a concrete name and will attempt to resolve it as is
498         // since the container should be able to resolve concretes automatically.
499         if (!isset($this->bindings[$abstract])) {
500             if ($this->missingLeadingSlash($abstract) && isset($this->bindings['\\'.$abstract])) {
501                 $abstract = '\\'.$abstract;
502             }
503 
504             return $abstract;
505         }
506 
507         return $this->bindings[$abstract]['concrete'];
508     }
509 
510     /**
511      * Determine if the given abstract has a leading slash.
512      *
513      * @param string $abstract
514      *
515      * @return bool
516      */
517     protected function missingLeadingSlash($abstract)
518     {
519         return is_string($abstract) && strpos($abstract, '\\') !== 0;
520     }
521 
522     /**
523      * Instantiate a concrete instance of the given type.
524      *
525      * @param string $concrete
526      * @param array  $parameters
527      *
528      * @return mixed
529      *
530      * @throws BindingResolutionException
531      */
532     public function build($concrete, $parameters = array())
533     {
534         // If the concrete type is actually a Closure, we will just execute it and
535         // hand back the results of the functions, which allows functions to be
536         // used as resolvers for more fine-tuned resolution of these objects.
537         if ($concrete instanceof Closure) {
538             return $concrete($this, $parameters);
539         }
540 
541         $reflector = new ReflectionClass($concrete);
542 
543         // If the type is not instantiable, the developer is attempting to resolve
544         // an abstract type such as an Interface of Abstract Class and there is
545         // no binding registered for the abstractions so we need to bail out.
546         if (!$reflector->isInstantiable()) {
547             $message = "Target [$concrete] is not instantiable.";
548 
549             throw new BindingResolutionException($message);
550         }
551 
552         $constructor = $reflector->getConstructor();
553 
554         // If there are no constructors, that means there are no dependencies then
555         // we can just resolve the instances of the objects right away, without
556         // resolving any other types or dependencies out of these containers.
557         if (is_null($constructor)) {
558             return new $concrete();
559         }
560 
561         $dependencies = $constructor->getParameters();
562 
563         // Once we have all the constructor's parameters we can create each of the
564         // dependency instances and then use the reflection instances to make a
565         // new instance of this class, injecting the created dependencies in.
566         $parameters = $this->keyParametersByArgument(
567             $dependencies, $parameters
568         );
569 
570         $instances = $this->getDependencies(
571             $dependencies, $parameters
572         );
573 
574         return $reflector->newInstanceArgs($instances);
575     }
576 
577     /**
578      * Resolve all of the dependencies from the ReflectionParameters.
579      *
580      * @param array $parameters
581      * @param array $primitives
582      *
583      * @return array
584      */
585     protected function getDependencies($parameters, array $primitives = array())
586     {
587         $dependencies = array();
588 
589         foreach ($parameters as $parameter) {
590             $dependency = $parameter->getClass();
591 
592             // If the class is null, it means the dependency is a string or some other
593             // primitive type which we can not resolve since it is not a class and
594             // we will just bomb out with an error since we have no-where to go.
595             if (array_key_exists($parameter->name, $primitives)) {
596                 $dependencies[] = $primitives[$parameter->name];
597             } elseif (is_null($dependency)) {
598                 $dependencies[] = $this->resolveNonClass($parameter);
599             } else {
600                 $dependencies[] = $this->resolveClass($parameter);
601             }
602         }
603 
604         return (array) $dependencies;
605     }
606 
607     /**
608      * Resolve a non-class hinted dependency.
609      *
610      * @param \ReflectionParameter $parameter
611      *
612      * @return mixed
613      *
614      * @throws BindingResolutionException
615      */
616     protected function resolveNonClass(ReflectionParameter $parameter)
617     {
618         if ($parameter->isDefaultValueAvailable()) {
619             return $parameter->getDefaultValue();
620         }
621 
622         $message = "Unresolvable dependency resolving [$parameter] in class {$parameter->getDeclaringClass()->getName()}";
623 
624         throw new BindingResolutionException($message);
625     }
626 
627     /**
628      * Resolve a class based dependency from the container.
629      *
630      * @param \ReflectionParameter $parameter
631      *
632      * @return mixed
633      *
634      * @throws BindingResolutionException
635      */
636     protected function resolveClass(ReflectionParameter $parameter)
637     {
638         try {
639             return $this->make($parameter->getClass()->name);
640         }
641 
642         // If we can not resolve the class instance, we will check to see if the value
643         // is optional, and if it is we will return the optional parameter value as
644         // the value of the dependency, similarly to how we do this with scalars.
645         catch (BindingResolutionException $e) {
646             if ($parameter->isOptional()) {
647                 return $parameter->getDefaultValue();
648             }
649 
650             throw $e;
651         }
652     }
653 
654     /**
655      * If extra parameters are passed by numeric ID, rekey them by argument name.
656      *
657      * @param array $dependencies
658      * @param array $parameters
659      *
660      * @return array
661      */
662     protected function keyParametersByArgument(array $dependencies, array $parameters)
663     {
664         foreach ($parameters as $key => $value) {
665             if (is_numeric($key)) {
666                 unset($parameters[$key]);
667 
668                 $parameters[$dependencies[$key]->name] = $value;
669             }
670         }
671 
672         return $parameters;
673     }
674 
675     /**
676      * Register a new resolving callback.
677      *
678      * @param string   $abstract
679      * @param \Closure $callback
680      */
681     public function resolving($abstract, Closure $callback)
682     {
683         $this->resolvingCallbacks[$abstract][] = $callback;
684     }
685 
686     /**
687      * Register a new resolving callback for all types.
688      *
689      * @param \Closure $callback
690      */
691     public function resolvingAny(Closure $callback)
692     {
693         $this->globalResolvingCallbacks[] = $callback;
694     }
695 
696     /**
697      * Fire all of the resolving callbacks.
698      *
699      * @param string $abstract
700      * @param mixed  $object
701      */
702     protected function fireResolvingCallbacks($abstract, $object)
703     {
704         if (isset($this->resolvingCallbacks[$abstract])) {
705             $this->fireCallbackArray($object, $this->resolvingCallbacks[$abstract]);
706         }
707 
708         $this->fireCallbackArray($object, $this->globalResolvingCallbacks);
709     }
710 
711     /**
712      * Fire an array of callbacks with an object.
713      *
714      * @param mixed $object
715      * @param array $callbacks
716      */
717     protected function fireCallbackArray($object, array $callbacks)
718     {
719         foreach ($callbacks as $callback) {
720             call_user_func($callback, $object, $this);
721         }
722     }
723 
724     /**
725      * Determine if a given type is shared.
726      *
727      * @param string $abstract
728      *
729      * @return bool
730      */
731     public function isShared($abstract)
732     {
733         if (isset($this->bindings[$abstract]['shared'])) {
734             $shared = $this->bindings[$abstract]['shared'];
735         } else {
736             $shared = false;
737         }
738 
739         return isset($this->instances[$abstract]) || $shared === true;
740     }
741 
742     /**
743      * Determine if the given concrete is buildable.
744      *
745      * @param mixed  $concrete
746      * @param string $abstract
747      *
748      * @return bool
749      */
750     protected function isBuildable($concrete, $abstract)
751     {
752         return $concrete === $abstract || $concrete instanceof Closure;
753     }
754 
755     /**
756      * Get the alias for an abstract if available.
757      *
758      * @param string $abstract
759      *
760      * @return string
761      */
762     protected function getAlias($abstract)
763     {
764         return isset($this->aliases[$abstract]) ? $this->aliases[$abstract] : $abstract;
765     }
766 
767     /**
768      * Get the container's bindings.
769      *
770      * @return array
771      */
772     public function getBindings()
773     {
774         return $this->bindings;
775     }
776 
777     /**
778      * Drop all of the stale instances and aliases.
779      *
780      * @param string $abstract
781      */
782     protected function dropStaleInstances($abstract)
783     {
784         unset($this->instances[$abstract], $this->aliases[$abstract]);
785     }
786 
787     /**
788      * Remove a resolved instance from the instance cache.
789      *
790      * @param string $abstract
791      */
792     public function forgetInstance($abstract)
793     {
794         unset($this->instances[$abstract]);
795     }
796 
797     /**
798      * Clear all of the instances from the container.
799      */
800     public function forgetInstances()
801     {
802         $this->instances = array();
803     }
804 
805     /**
806      * Determine if a given offset exists.
807      *
808      * @param string $key
809      *
810      * @return bool
811      */
812     public function offsetExists($key)
813     {
814         return isset($this->bindings[$key]);
815     }
816 
817     /**
818      * Get the value at a given offset.
819      *
820      * @param string $key
821      *
822      * @return mixed
823      */
824     public function offsetGet($key)
825     {
826         return $this->make($key);
827     }
828 
829     /**
830      * Set the value at a given offset.
831      *
832      * @param string $key
833      * @param mixed  $value
834      */
835     public function offsetSet($key, $value)
836     {
837         // If the value is not a Closure, we will make it one. This simply gives
838         // more "drop-in" replacement functionality for the Pimple which this
839         // container's simplest functions are base modeled and built after.
840         if (!$value instanceof Closure) {
841             $value = function () use ($value) {
842                 return $value;
843             };
844         }
845 
846         $this->bind($key, $value);
847     }
848 
849     /**
850      * Unset the value at a given offset.
851      *
852      * @param string $key
853      */
854     public function offsetUnset($key)
855     {
856         unset($this->bindings[$key], $this->instances[$key], $this->resolved[$key]);
857     }
858 
859     /**
860      * Dynamically access container services.
861      *
862      * @param string $key
863      *
864      * @return mixed
865      */
866     public function __get($key)
867     {
868         return $this[$key];
869     }
870 
871     /**
872      * Dynamically set container services.
873      *
874      * @param string $key
875      * @param mixed  $value
876      */
877     public function __set($key, $value)
878     {
879         $this[$key] = $value;
880     }
881 }
882 
LFT API documentation generated by ApiGen