Remove the dependence of illuminate/container from Laravel for flexible use in non-Laravel frames, and take a look at the illuminate/container annotation. Easy to understand Laravel containers.
A link to the
- Github.com/guanguans/d…
- Github.com/illuminate/…
code
/*
* This file is part of the guanguans/di.
*
* (c) guanguans <ityaozm@gmail.com>
*
* This source file is subject to the MIT license that is bundled.
*/
namespace Guanguans\Di;
use ArrayAccess;
use Closure;
use LogicException;
use Psr\Container\ContainerInterface;
use ReflectionClass;
use ReflectionParameter;
/**
* This file is modified from `illuminate/container`.
*
* @see https://github.com/illuminate/container
*/
class Container implements ArrayAccess.ContainerInterface
{
/** * The current globally available container (if any). * Globally available containers (if any). * *@var static
*/
protected static $instance;
/** * An array of the types that have been resolved. * *@var array
*/
protected $resolved = [];
/** * The container's bindings. * *@var array
*/
protected $bindings = [];
/** * The container's method bindings. * *@var array
*/
protected $methodBindings = [];
/** * The container's shared instances. * *@var array
*/
protected $instances = [];
/** * The registered type aliases. * *@var array
*/
protected $aliases = [];
/** * The registered aliases keyed by The abstract name. * *@var array
*/
protected $abstractAliases = [];
/** * The extension closure for services. * *@var array
*/
protected $extenders = [];
/** * All of the registered tags. * *@var array
*/
protected $tags = [];
/** * The stack of Concretions currently being built. * *@var array
*/
protected $buildStack = [];
/** * The parameter overrides The stack. * *@var array
*/
protected $with = [];
/** * The contextual binding map. * *@var array
*/
public $contextual = [];
/** * All of the registered rebound callbacks. * *@var array
*/
protected $reboundCallbacks = [];
/** * All of the global considerations callbacks. * *@var array
*/
protected $globalResolvingCallbacks = [];
Resolving callbacks /** * All of the global after considerations callbacks. * *@var array
*/
protected $globalAfterResolvingCallbacks = [];
/** * All of the considerations callbacks by class type. * *@var array
*/
protected $resolvingCallbacks = [];
/** * All of the after considerations callbacks by class type. * *@var array
*/
protected $afterResolvingCallbacks = [];
/** * Define a contextual binding. * *@param string $concrete
* @return \Guanguans\Di\ContextualBindingBuilder
*/
public function when($concrete)
{
return new ContextualBindingBuilder($this.$this->getAlias($concrete));
}
/** * Determine if the given abstract type has been bound. * *@param string $abstract
* @return bool
*/
public function bound($abstract)
{
return isset($this->bindings[$abstract) | |isset($this->instances[$abstract) | |$this->isAlias($abstract);
}
/** * Determine if the given abstract type has been resolved * *@param string $abstract
* @return bool
*/
public function resolved($abstract)
{
if ($this->isAlias($abstract)) {
$abstract = $this->getAlias($abstract);
}
return isset($this->resolved[$abstract) | |isset($this->instances[$abstract]);
}
/** * Determine if a given type is shared. * *@param string $abstract
* @return bool
*/
public function isShared($abstract)
{
return isset($this->instances[$abstract) | | (isset($this->bindings[$abstract] ['shared'&&])$this->bindings[$abstract] ['shared'= = =true);
}
/** * Determine if a given string is an alias. * Determine if the given string is an alias@param string $name
* @return bool
*/
public function isAlias($name)
{
return isset($this->aliases[$name]);
}
/** * Register a binding with the container@param string|array $abstract
* @param \Closure|string|null $concrete
* @param bool $shared
* @return void
*/
public function bind($abstract.$concrete = null.$shared = false)
{
// If no concrete type was given, we will simply set the concrete type to the
// abstract type. After that, the concrete type to be registered as shared
// without being forced to state their classes in both of the parameters.
// If no concrete type is given, we simply set the concrete type to an abstract type.
// After that, you register as a shared concrete type without having to declare its class in two parameters.
$this->dropStaleInstances($abstract);
if (is_null($concrete)) {
$concrete = $abstract;
}
// If the factory is not a Closure, it means it is just a class name which is
// bound into this container to the abstract type and we will just wrap it
// up inside its own Closure to give us more convenience when extending.
// If the factory is not a Closure, that means it is just a class name,
// The class name is bound to the container, bound to the abstract type,
// We wrapped it in our Closure to make it easier for us to expand.
if (! $concrete instanceof Closure) {
$concrete = $this->getClosure($abstract.$concrete);
}
$this->bindings[$abstract] = compact('concrete'.'shared');
// If the abstract type was already resolved in this container we'll fire the
// rebound listener so that any objects which have already gotten resolved
// can have their copy of the object updated via the listener callbacks.
// If the abstract type has been resolved in the container, we will fire the rebound listener,
// So that all parsed objects can update their copy of the object via listener callbacks.
if ($this->resolved($abstract)) {
$this->rebound($abstract); }}/** * Get the Closure to be used when building a type. * *@param string $abstract
* @param string $concrete
* @return \Closure
*/
protected function getClosure($abstract.$concrete)
{
return function ($container.$parameters = []) use ($abstract.$concrete) {
if ($abstract= =$concrete) {
return $container->build($concrete);
}
return $container->makeWith($concrete.$parameters);
};
}
/** * Determine if the container has a method binding. * *@param string $method
* @return bool
*/
public function hasMethodBinding($method)
{
return isset($this->methodBindings[$method]);
}
/** * Bind a callback to resolve with Container::call. * Bind a callback to resolve with Container::call. * *@param string $method
* @param \Closure $callback
* @return void
*/
public function bindMethod($method.$callback)
{
$this->methodBindings[$method] = $callback;
}
/** * Get the method binding for the given method. * *@param string $method
* @param mixed $instance
* @return mixed
*/
public function callMethodBinding($method.$instance)
{
return call_user_func($this->methodBindings[$method].$instance.$this);
}
/** * Add a contextual binding to the container. * *@param string $concrete
* @param string $abstract
* @param \Closure|string $implementation
* @return void
*/
public function addContextualBinding($concrete.$abstract.$implementation)
{
$this->contextual[$concrete] [$this->getAlias($abstract)] = $implementation;
}
/** * Register a binding if it hasn't already been registered. * *@param string $abstract
* @param \Closure|string|null $concrete
* @param bool $shared
* @return void
*/
public function bindIf($abstract.$concrete = null.$shared = false)
{
if (! $this->bound($abstract)) {
$this->bind($abstract.$concrete.$shared); }}/** * Register a shared binding in the container. * *@param string|array $abstract
* @param \Closure|string|null $concrete
* @return void
*/
public function singleton($abstract.$concrete = null)
{
$this->bind($abstract.$concrete.true);
}
/** * "Extend" an abstract type in the container. * *@param string $abstract
* @param \Closure $closure
* @return void
*
* @throws \InvalidArgumentException
*/
public function extend($abstract.Closure $closure)
{
$abstract = $this->getAlias($abstract);
if (isset($this->instances[$abstract]) {$this->instances[$abstract] = $closure($this->instances[$abstract].$this);
$this->rebound($abstract);
} else {
$this->extenders[$abstract=] []$closure;
if ($this->resolved($abstract)) {
$this->rebound($abstract); }}}/** * Register an existing instance as shared in the container. * *@param string $abstract
* @param mixed $instance
* @return void
*/
public function instance($abstract.$instance)
{
$this->removeAbstractAlias($abstract);
$isBound = $this->bound($abstract);
unset($this->aliases[$abstract]);
// We'll check to determine if this type has been bound before, and if it has
// we will fire the rebound callbacks registered with the container and it
// can be updated with consuming classes that have gotten resolved here.
// We will check to see if this type has been previously bound,
// If it is already bound, it triggers a rebound callback registered in the container,
// And can be updated using the consumable classes resolved here.
$this->instances[$abstract] = $instance;
if ($isBound) {
$this->rebound($abstract); }}/** * Remove an alias from the contextual binding alias cache. * Remove an alias from the contextual binding alias cache. * *@param string $searched
* @return void
*/
protected function removeAbstractAlias($searched)
{
if (! isset($this->aliases[$searched]) {return;
}
foreach ($this->abstractAliases as $abstract= >$aliases) {
foreach ($aliases as $index= >$alias) {
if ($alias= =$searched) {
unset($this->abstractAliases[$abstract] [$index]); }}}}/** * Assign a set of tags to a given binding. * *@param array|string $abstracts
* @paramarray|mixed ... $tags *@return void
*/
public function tag($abstracts.$tags)
{
$tags = is_array($tags)?$tags : array_slice(func_get_args(), 1);
foreach ($tags as $tag) {
if (! isset($this->tags[$tag]) {$this->tags[$tag] = [];
}
foreach ((array) $abstracts as $abstract) {
$this->tags[$tag=] []$abstract; }}}/** * Resolve all of the bindings for a given tag. * *@param string $tag
* @return array
*/
public function tagged($tag)
{
$results = [];
if (isset($this->tags[$tag]) {foreach ($this->tags[$tag] as $abstract) {
$results[] = $this->make($abstract); }}return $results;
}
/** * Alias a type to a different name. * *@param string $abstract
* @param string $alias
* @return void
*/
public function alias($abstract.$alias)
{
$this->aliases[$alias] = $abstract;
$this->abstractAliases[$abstract=] []$alias;
}
/** * Bind a new callback to an abstract's rebind event. * *@param string $abstract
* @param \Closure $callback
* @return mixed
*/
public function rebinding($abstract.Closure $callback)
{
$this->reboundCallbacks[$abstract = $this->getAlias($abstract[] =)]$callback;
if ($this->bound($abstract)) {
return $this->make($abstract); }}/** * Refresh an instance on the given target and method. * *@param string $abstract
* @param mixed $target
* @param string $method
* @return mixed
*/
public function refresh($abstract.$target.$method)
{
return $this->rebinding($abstract.function ($app.$instance) use ($target.$method) {
$target- > {$method} ($instance);
});
}
/** * Fire the "rebound" callbacks for the given abstract type. * *@param string $abstract
* @return void
*/
protected function rebound($abstract)
{
$instance = $this->make($abstract);
foreach ($this->getReboundCallbacks($abstract) as $callback) {
call_user_func($callback.$this.$instance); }}/** * Get the rebound callbacks for a given type@param string $abstract
* @return array
*/
protected function getReboundCallbacks($abstract)
{
if (isset($this->reboundCallbacks[$abstract]) {return $this->reboundCallbacks[$abstract];
}
return [];
}
/** * Wrap the given closure such that its dependencies will be injected when executed. * *@param \Closure $callback
* @param array $parameters
* @return \Closure
*/
public function wrap(Closure $callback.array $parameters = [])
{
return function () use ($callback.$parameters) {
return $this->call($callback.$parameters);
};
}
/**
* Call the given Closure / class@methodAnd inject its dependencies. * Call the given Closure/class@methodAnd inject its dependencies. * *@param callable|string $callback
* @param array $parameters
* @param string|null $defaultMethod
* @return mixed
*/
public function call($callback.array $parameters= [].$defaultMethod = null)
{
return BoundMethod::call($this.$callback.$parameters.$defaultMethod);
}
/** * Get a closure to resolve the given type from the container. * Get a closure to resolve the given type from the container. * *@param string $abstract
* @return \Closure
*/
public function factory($abstract)
{
return function () use ($abstract) {
return $this->make($abstract);
};
}
/** * Resolve the given type with the given parameter overrides. * *@param string $abstract
* @param array $parameters
* @return mixed
*/
public function makeWith($abstract.array $parameters)
{
return $this->resolve($abstract.$parameters);
}
/** * Resolve the given type from the container. * *@param string $abstract
* @return mixed
*/
public function make($abstract)
{
return $this->resolve($abstract);
}
/** * Resolve the given type from the container. * *@param string $abstract
* @param array $parameters
* @return mixed
*/
protected function resolve($abstract.$parameters = [])
{
$abstract = $this->getAlias($abstract);
$needsContextualBuild=!empty($parameters) || ! is_null(
$this->getContextualConcrete($abstract));// If an instance of the type is currently being managed as a singleton we'll
// just return an existing instance instead of instantiating new instances
// so the developer can keep using the same objects instance every time.
// If you are currently managing instances of this type singleton,
// Instead of instantiating a new instance, we will only return an existing instance,
// So that developers can continue to use the same object instance each time.
if (isset($this->instances[$abstract]) &&!$needsContextualBuild) {
return $this->instances[$abstract];
}
$this->with[] = $parameters;
$concrete = $this->getConcrete($abstract);
// We're ready to instantiate an instance of the concrete type registered for
// the binding. This will instantiate the types, as well as resolve any of
// its "nested" dependencies recursively until all have gotten resolved.
// We are ready to instantiate an instance of the specific type registered by the binding.
// This instantiates the type and resolves any of its "nested" dependencies recursively until all are resolved.
if ($this->isBuildable($concrete.$abstract)) {
$object = $this->build($concrete);
} else {
$object = $this->make($concrete);
}
// If we defined any extenders for this type, we'll need to spin through them
// and apply them to the object being built. This allows for the extension
// of services, such as changing configuration or decorating the object.
// If we define any extenders for this type, we need to iterate over them and apply them to the objects we are building.
// This allows you to extend the service, such as changing configurations or decorating objects.
foreach ($this->getExtenders($abstract) as $extender) {
$object = $extender($object.$this);
}
// If the requested type is registered as a singleton we'll want to cache off
// the instances in "memory" so we can return it later without creating an
// entirely new instance of an object on each subsequent request for it.
// If the type of request is registered as a singleton, we will cache the instance in "memory",
// So that we can return it later without having to create a new instance of the object on each subsequent request.
if ($this->isShared($abstract) &&!$needsContextualBuild) {
$this->instances[$abstract] = $object;
}
$this->fireResolvingCallbacks($abstract.$object);
// Before returning, we will also set the resolved flag to "true" and pop off
// the parameter overrides for this build. After those two things are done
// we will be ready to return back the fully constructed class instance.
// Before returning, we also set the parsing flag to "true" and pop up this version's argument substitution.
// With these two things done, we are ready to return the fully constructed class instance.
$this->resolved[$abstract] = true;
array_pop($this->with);
return $object;
}
/** * Get the concrete type for a given abstract. * *@param string $abstract
* @return mixed $concrete
*/
protected function getConcrete($abstract)
{
if (! is_null($concrete = $this->getContextualConcrete($abstract))) {
return $concrete;
}
// If we don't have a registered resolver or concrete for the type, we'll just
// assume each type is a concrete name and will attempt to resolve it as is
// since the container should be able to resolve concretes automatically.
// If we do not have a registered parser or concrete object for that type, we will assume that each type is concrete name,
// And try to parse it as is, because the container should be able to parse concrete objects automatically.
if (isset($this->bindings[$abstract]) {return $this->bindings[$abstract] ['concrete'];
}
return $abstract;
}
/** * Get the contextual concrete binding for the given abstract. * Get the contextual concrete binding for the given abstract. * *@param string $abstract
* @return string|null
*/
protected function getContextualConcrete($abstract)
{
if (! is_null($binding = $this->findInContextualBindings($abstract))) {
return $binding;
}
// Next we need to see if a contextual binding might be bound under an alias of the
// given abstract type. So, we will need to check if any aliases exist with this
// type and then spin through them and check for contextual bindings on these.
// Next, we need to see if the context binding can be bound under the alias of the given abstract type.
// Therefore, we will need to check if aliases exist for this type, then rotate them and check the context bindings for these aliases.
if (empty($this->abstractAliases[$abstract]) {return;
}
foreach ($this->abstractAliases[$abstract] as $alias) {
if (! is_null($binding = $this->findInContextualBindings($alias))) {
return $binding; }}}/** * Find the concrete binding for the given abstract in the contextual binding array. ** Find the specific binding for the given abstract in the contextual binding array@param string $abstract
* @return string|null
*/
protected function findInContextualBindings($abstract)
{
if (isset($this->contextual[end($this->buildStack)][$abstract]) {return $this->contextual[end($this->buildStack)][$abstract]; }}/** * Determine if the given concrete is buildable. * *@param mixed $concrete
* @param string $abstract
* @return bool
*/
protected function isBuildable($concrete.$abstract)
{
return $concrete= = =$abstract || $concrete instanceof Closure;
}
/* Instantiate a concrete instance of the given type. * *@param string $concrete
* @return mixed
*
* @throws \Guanguans\Di\BindingResolutionException
*/
public function build($concrete)
{
// If the concrete type is actually a Closure, we will just execute it and
// hand back the results of the functions, which allows functions to be
// used as resolvers for more fine-tuned resolution of these objects.
// If the concrete type is actually Closure, we will execute it directly and return the result of the function,
// This allows functions to be used as parsers for finer parsing of these objects.
if ($concrete instanceof Closure) {
return $concrete($this.$this->getLastParameterOverride());
}
$reflector = new ReflectionClass($concrete);
// If the type is not instantiable, the developer is attempting to resolve
// an abstract type such as an Interface of Abstract Class and there is
// no binding registered for the abstractions so we need to bail out.
// If the type is not instantiable, the developer is trying to resolve the abstract type,
// For example, the Abstract Class interface, and no bindings are registered for the abstraction, so we need to bail it out.
if (! $reflector->isInstantiable()) {
return $this->notInstantiable($concrete);
}
$this->buildStack[] = $concrete;
$constructor = $reflector->getConstructor();
// If there are no constructors, that means there are no dependencies then
// we can just resolve the instances of the objects right away, without
// resolving any other types or dependencies out of these containers.
// If there is no constructor, that means there are no dependencies, we can immediately parse the instance of the object,
// Without resolving any other types or dependencies from these containers.
if (is_null($constructor)) {
array_pop($this->buildStack);
return new $concrete;
}
$dependencies = $constructor->getParameters();
// Once we have all the constructor's parameters we can create each of the
// dependency instances and then use the reflection instances to make a
// new instance of this class, injecting the created dependencies in.
// Once we have all the constructor arguments, we can create each dependency instance,
// Then use the reflection instance to create a new instance of this class and inject the created dependencies into it.
$instances = $this->resolveDependencies(
$dependencies
);
array_pop($this->buildStack);
return $reflector->newInstanceArgs($instances);
}
/** * Resolve all of the dependencies from the ReflectionParameters. * *@param array $dependencies
* @return array
*/
protected function resolveDependencies(array $dependencies)
{
$results = [];
foreach ($dependencies as $dependency) {
// If this dependency has a override for this particular build we will use
// that instead as the value. Otherwise, we will continue with this run
// of resolutions and let reflection attempt to determine the result.
// If this dependency has an alternative to this particular build, we will use it as a value.
// Otherwise, we will continue to perform the resolution and let reflection try to determine the result.
if ($this->hasParameterOverride($dependency)) {
$results[] = $this->getParameterOverride($dependency);
continue;
}
// If the class is null, it means the dependency is a string or some other
// primitive type which we can not resolve since it is not a class and
// we will just bomb out with an error since we have no-where to go.
// If this class is null, that means the dependency is a primitive type of a string or other type,
// Since it is not a class, we cannot parse it, and since there is no location, we will throw an error.
$results[] = is_null($class = $dependency->getClass())
? $this->resolvePrimitive($dependency)
: $this->resolveClass($dependency);
}
return $results;
}
/** * Determine if the given dependency has a parameter override from makeWith. * *@param \ReflectionParameter $dependency
* @return bool
*/
protected function hasParameterOverride($dependency)
{
return array_key_exists(
$dependency->name,
$this->getLastParameterOverride()
);
}
/** * Get a parameter override for a dependency. * *@param \ReflectionParameter $dependency
* @return mixed
*/
protected function getParameterOverride($dependency)
{
return $this->getLastParameterOverride()[$dependency->name];
}
/** * Get the last parameter override. * *@return array
*/
protected function getLastParameterOverride()
{
return count($this->with) ? end($this->with) : [];
}
/** * Resolve a non-class hinted primitive dependency. * *@param \ReflectionParameter $parameter
* @return mixed
*
* @throws \Guanguans\Di\BindingResolutionException
*/
protected function resolvePrimitive(ReflectionParameter $parameter)
{
if (! is_null($concrete = $this->getContextualConcrete('$'.$parameter->name))) {
return $concrete instanceof Closure ? $concrete($this) : $concrete;
}
if ($parameter->isDefaultValueAvailable()) {
return $parameter->getDefaultValue();
}
$this->unresolvablePrimitive($parameter);
}
/** * Resolve class based dependency from the container. * *@param \ReflectionParameter $parameter
* @return mixed
*
* @throws \Guanguans\Di\BindingResolutionException
*/
protected function resolveClass(ReflectionParameter $parameter)
{
try {
return $this->make($parameter->getClass()->name);
}
// If we can not resolve the class instance, we will check to see if the value
// is optional, and if it is we will return the optional parameter value as
// the value of the dependency, similarly to how we do this with scalars.
// If the class instance cannot be resolved, the value is checked to see if it is optional. If it is,
// they return the optional argument value as the value of the dependency, similar to a scalar in the way this operation is performed.
catch (BindingResolutionException $e) {
if ($parameter->isOptional()) {
return $parameter->getDefaultValue();
}
throw $e; }}/** * Throw an exception that concrete is not instantiable. * *@param string $concrete
* @return void
*
* @throws \Guanguans\Di\BindingResolutionException
*/
protected function notInstantiable($concrete)
{
if (! empty($this->buildStack)) {
$previous = implode(', '.$this->buildStack);
$message = "Target [$concrete] is not instantiable while building [$previous].";
} else {
$message = "Target [$concrete] is not instantiable.";
}
throw new BindingResolutionException($message);
}
/** * Throw an exception for an unresolvable primitive. * *@param \ReflectionParameter $parameter
* @return void
*
* @throws \Guanguans\Di\BindingResolutionException
*/
protected function unresolvablePrimitive(ReflectionParameter $parameter)
{
$message = "Unresolvable dependency resolving [$parameter] in class {$parameter->getDeclaringClass()->getName()}";
throw new BindingResolutionException($message);
}
/** * Register a new resolving callback. * Register a new resolving callback. * *@param string $abstract
* @param \Closure|null $callback
* @return void
*/
public function resolving($abstract.Closure $callback = null)
{
if (is_string($abstract)) {
$abstract = $this->getAlias($abstract);
}
if (is_null($callback) && $abstract instanceof Closure) {
$this->globalResolvingCallbacks[] = $abstract;
} else {
$this->resolvingCallbacks[$abstract=] []$callback; }}/** * Register a new after resolving callback for all types. * *@param string $abstract
* @param \Closure|null $callback
* @return void
*/
public function afterResolving($abstract.Closure $callback = null)
{
if (is_string($abstract)) {
$abstract = $this->getAlias($abstract);
}
if ($abstract instanceof Closure && is_null($callback)) {
$this->globalAfterResolvingCallbacks[] = $abstract;
} else {
$this->afterResolvingCallbacks[$abstract=] []$callback; }}/** * Fire all of the resolving callbacks. * *@param string $abstract
* @param mixed $object
* @return void
*/
protected function fireResolvingCallbacks($abstract.$object)
{
$this->fireCallbackArray($object.$this->globalResolvingCallbacks);
$this->fireCallbackArray(
$object.$this->getCallbacksForType($abstract.$object.$this->resolvingCallbacks)
);
$this->fireAfterResolvingCallbacks($abstract.$object);
}
/** * Fire all of the after considerations callbacks. * *@param string $abstract
* @param mixed $object
* @return void
*/
protected function fireAfterResolvingCallbacks($abstract.$object)
{
$this->fireCallbackArray($object.$this->globalAfterResolvingCallbacks);
$this->fireCallbackArray(
$object.$this->getCallbacksForType($abstract.$object.$this->afterResolvingCallbacks)
);
}
/** * Get all callbacks for a given type. * *@param string $abstract
* @param object $object
* @param array $callbacksPerType
*
* @return array
*/
protected function getCallbacksForType($abstract.$object.array $callbacksPerType)
{
$results = [];
foreach ($callbacksPerType as $type= >$callbacks) {
if ($type= = =$abstract || $object instanceof $type) {
$results = array_merge($results.$callbacks); }}return $results;
}
/** * Fire an array of callbacks with an object. * *@param mixed $object
* @param array $callbacks
* @return void
*/
protected function fireCallbackArray($object.array $callbacks)
{
foreach ($callbacks as $callback) {
$callback($object.$this); }}/** * Get the container's bindings. * *@return array
*/
public function getBindings()
{
return $this->bindings;
}
/** * Get the alias for an abstract if available. * *@param string $abstract
* @return string
*
* @throws \LogicException
*/
public function getAlias($abstract)
{
if (! isset($this->aliases[$abstract]) {return $abstract;
}
if ($this->aliases[$abstract= = =$abstract) {
throw new LogicException("[{$abstract}] is aliased to itself.");
}
return $this->getAlias($this->aliases[$abstract]);
}
/** * Get the extender callbacks for a given type. * *@param string $abstract
* @return array
*/
protected function getExtenders($abstract)
{
$abstract = $this->getAlias($abstract);
if (isset($this->extenders[$abstract]) {return $this->extenders[$abstract];
}
return [];
}
/** * Remove all of the extender callbacks for a given type. * *@param string $abstract
* @return void
*/
public function forgetExtenders($abstract)
{
unset($this->extenders[$this->getAlias($abstract)]);
}
/** * Drop all of the stale instances and aliases. * *@param string $abstract
* @return void
*/
protected function dropStaleInstances($abstract)
{
unset($this->instances[$abstract].$this->aliases[$abstract]);
}
/** * Remove resolved instance from the instance cache. * *@param string $abstract
* @return void
*/
public function forgetInstance($abstract)
{
unset($this->instances[$abstract]);
}
/** * Clear all instances from the container. * *@return void
*/
public function forgetInstances()
{
$this->instances = [];
}
/** * Flush the container of all bindings and resolved instances. * *@return void
*/
public function flush()
{
$this->aliases = [];
$this->resolved = [];
$this->bindings = [];
$this->instances = [];
$this->abstractAliases = [];
}
/** * Set the globally available instance of the container. * *@return static
*/
public static function getInstance()
{
if (is_null(static: :$instance)) {
static: :$instance = new static;
}
return static: :$instance;
}
/** * Set the shared instance of the container. * *@param \Guanguans\Di\Container|null $container
* @return static
*/
public static function setInstance(Container $container = null)
{
return static: :$instance = $container;
}
/** * Determine if a given offset exists. * Determine whether the given key exists. * *@param string $key
* @return bool
*/
public function offsetExists($key)
{
return $this->bound($key);
}
/** * Get the value at a given offset. * *@param string $key
* @return mixed
*/
public function offsetGet($key)
{
return $this->make($key);
}
/** * Set the value at a given offset. * Set the value to the given key. * *@param string $key
* @param mixed $value
* @return void
*/
public function offsetSet($key.$value)
{
$this->bind($key.$value instanceof Closure ? $value : function () use ($value) {
return $value;
});
}
/** * Unset the value at a given offset. * Unset the value with the given key. * *@param string $key
* @return void
*/
public function offsetUnset($key)
{
unset($this->bindings[$key].$this->instances[$key].$this->resolved[$key]);
}
/** * * *@param string $key
* @return mixed
*/
public function __get($key)
{
return $this[$key];
}
/** 1 * *@param string $key
* @param mixed $value
* @return void
*/
public function __set($key.$value)
{
$this[$key] = $value;
}
/** * finds the container's entry by its identifier and returns it. * *@inheritDoc* /
public function has($id)
{
return $this->offsetExists($id);
}
/** * Returns true if the container can return an entry with the given identifier. Otherwise return false. * *@inheritDoc* /
public function get($id)
{
return $this[$id]; }}Copy the code