@param string          $abstract
@param string|callable $concrete

@throws \InvalidArgumentException
426407
public function addAlias($abstract, $concrete)
    {
        if (is_string($concrete)) {
            if ($concrete[0] === '\\') {
                //Strip all leading backslashes if $concrete is a class name
                $concrete = substr($concrete, 1);
            }
        } elseif (!is_callable($concrete)) {
            throw new \InvalidArgumentException('The alias must either be a class name or a callable');
        }
        //Strip all leading backslashes
        if ($abstract[0] === '\\') {
            $abstract = substr($abstract, 1);
        }
        $this->aliases[$abstract] = $concrete;
    }
914586
protected function resolve($abstract, array $parameters = [])
    {
        if ($this->bound($abstract)) {
            array_unshift($parameters, $this);

            return call_user_func_array($this->bindings[$abstract]['concrete'], $parameters);
        }

        $reflector = new ReflectionClass($abstract);

        if (!$constructor = $reflector->getConstructor()) {
            return new $abstract($parameters);
        }

        $constructorParams = $constructor->getParameters();

        $callParams = [];

        foreach ($constructorParams as $param) {
            if ($param->getClass()) {
                $callParams[] = $this->__invoke($param->getClass()->getName());
            }
        }

        foreach ($parameters as $key => $value) {
            $callParams[] = $value;
        }

        return $reflector->newInstanceArgs($callParams);
    }
1210130
public function isSingleton(string $abstract) : bool
    {
        if (! $this->has($abstract)) {
            throw new NotFoundException("Element '$abstract' not found");
        }

        return $this->collection[$abstract] instanceof Closure === false;
    }
403933
public function extend($abstract, Closure $closure)
    {
        if (! isset($this->bindings[$abstract])) {
            throw new \InvalidArgumentException("Type {$abstract} is not bound.");
        }

        if (isset($this->instances[$abstract])) {
            $this->instances[$abstract] = $closure($this->instances[$abstract], $this);

            $this->rebound($abstract);
        } else {
            $extender = $this->getExtender($abstract, $closure);

            $this->bind($abstract, $extender, $this->isShared($abstract));
        }
    }
825896
public function extend($abstract, \Closure $closure)
        {
            if (!Arrays::exists($abstract, $this->bindings)) {
                throw new \InvalidArgumentException("Type {$abstract} is not bound.");
            }
            // To "extend" a binding, we will grab the old "resolver" Closure and pass it
            // into a new one. The old resolver will be called first and the result is
            // handed off to the "new" resolver, along with this container instance.
            $resolver = $this->bindings[$abstract]['concrete'];
            $this->bind($abstract, function($container) use ($resolver, $closure) {
                return $closure($resolver($container), $container);
            }, $this->isShared($abstract));
        }
376048
public function bind($abstract, $concrete = null, $shared = false)
    {
        $this->dropStaleInstances($abstract);

        // 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 (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 (! $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 ($this->resolved($abstract)) {
            $this->rebound($abstract);
        }
    }
1265443
public function resolve($concrete, $params)
    {
        if ($concrete instanceof \Closure) {
            return $concrete($this, $params);
        }
        $reflector = new \ReflectionClass($concrete);
        // check if class is instantiable
        if (!$reflector->isInstantiable()) {
            throw new \Exception("Class {$concrete} is not instantiable", 500);
        }
        // get class constructor
        $constructor = $reflector->getConstructor();
        if (is_null($constructor)) {
            // get new instance from class
            return $reflector->newInstance();
        }
        // get constructor params
        $parameters = $constructor->getParameters();
        $dependencies = $this->getResolveDependencies($parameters, $params);
        // get new instance with dependencies resolved
        return $reflector->newInstanceArgs($dependencies);
    }
276584
public function bind(string $scope, string $abstract, string $concrete)
    {
        $this->validateScope(__METHOD__, $scope);

        if ($scope === self::SCOPE_INSTANCE_PER_RESOLVE) {
            $this->container->bind($abstract, $concrete);
        } else {
            $this->container->singleton($abstract, $concrete);
        }
    }
50155
protected function getClosure($abstract, $concrete)
    {
        return function ($container, $parameters = []) use ($abstract, $concrete) {
            if ($abstract == $concrete) {
                return $container->build($concrete);
            }

            return $container->resolve(
                $concrete, $parameters, $raiseEvents = false
            );
        };
    }
491299
protected function getConcrete( $abstract ) {

		$concrete = false;
		$abstract = $this->getAbstract( $abstract );

		if ( $this->has( $abstract ) ) {
			$concrete = $this->bindings[ $abstract ]['concrete'];
		}

		return $concrete ?: $abstract;
	}
1303048
public function make($concrete, array $args = [])
    {
        // build only from strings
        if (!is_object($concrete) && !is_scalar($concrete) && !is_null($concrete)) {
            throw new Exceptions\InvalidArgumentException();
        }

        // get reflection and parameters
        $reflection = new \ReflectionClass($concrete);
        $constructor = $reflection->getConstructor();

        // Return new instance
        $arguments = $constructor ? $this->inject($constructor, $args) : [];
        return $reflection->newInstanceArgs($arguments);
    }
81230
protected function fireResolvingCallbacks($abstract, $object)
	{
		$this->fireCallbackArray($object, $this->globalResolvingCallbacks);

		$this->fireCallbackArray(
			$object, $this->getCallbacksForType(
				$abstract, $object, $this->resolvingCallbacks
			)
		);

		$this->fireCallbackArray($object, $this->globalAfterResolvingCallbacks);

		$this->fireCallbackArray(
			$object, $this->getCallbacksForType(
				$abstract, $object, $this->afterResolvingCallbacks
			)
		);
	}
232998
public function resolve( $abstract, array $parameters = [] ) {

		// Get the true abstract name.
		$abstract = $this->getAbstract( $abstract );

		// If this is being managed as an instance and we already have
		// the instance, return it now.
		if ( isset( $this->instances[ $abstract ] ) ) {

			return $this->instances[ $abstract ];
		}

		// Get the concrete implementation.
		$concrete = $this->getConcrete( $abstract );

		// If we can't build an object, assume we should return the value.
		if ( ! $this->isBuildable( $concrete ) ) {

			// If we don't actually have this, return false.
			if ( ! $this->has( $abstract ) ) {
				return false;
			}

			return $concrete;
		}

		// Build the object.
		$object = $this->build( $concrete, $parameters );

		if ( ! $this->has( $abstract ) ) {
			return $object;
		}

		// If shared instance, make sure to store it in the instances
		// array so that we're not creating new objects later.
		if ( $this->bindings[ $abstract ]['shared'] && ! isset( $this->instances[ $abstract ] ) ) {

			$this->instances[ $abstract ] = $object;
		}

		// Run through each of the extensions for the object.
		foreach ( $this->extensions[ $abstract ] as $extension ) {

			$object = new $extension( $object, $this );
		}

		// Return the object.
		return $object;
	}
1207468
protected function getConcrete($abstract)
		{
			// 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 Eventable should be able to resolve concretes automatically.
			if ( ! isset($this->bindings[$abstract])) {
				if ($this->missingLeadingSlash($abstract) && isset($this->bindings['\\' . $abstract])) {
					$abstract = '\\' . $abstract;
				}

				return $abstract;
			} else {
				return $this->bindings[$abstract]['concrete'];
			}
		}
887502
public function alias($aliasName, $concreteName)
    {
        if ( !is_string($concreteName) ) {
            throw new \InvalidArgumentException('Concrete name must be a string');
        }
        $this->aliases[ $aliasName ] = $concreteName;

        return $this;
    }
826056
protected function getContextualConcrete($abstract)
  {
    if (isset($this->contextual[end($this->buildStack)][$abstract])) {
      return $this->contextual[end($this->buildStack)][$abstract];
    }
  }
878510
public function bind($abstract, $concrete = null, $shared = false)
		{
			// If the given types are actually an array, we will assume an alias is being
			// defined and will grab this "real" abstract class name and register this
			// alias with the container so that it can be used as a shortcut for it.
			if (Arrays::is($abstract)) {
				list($abstract, $alias) = $this->extractAlias($abstract);

				$this->alias($abstract, $alias);
			}

			// If no concrete type was given, we will simply set the concrete type to the
			// abstract type. This will allow concrete type to be registered as shared
			// without being forced to state their classes in both of the parameter.
			$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
			// is bound into this container to the abstract type and we will just wrap
			// it up inside a Closure to make things more convenient when extending.
			if ( ! $concrete instanceof Closure) {
				$concrete = $this->getClosure($abstract, $concrete);
			}

			$bound = $this->bound($abstract);

			$this->bindings[$abstract] = compact('concrete', 'shared');

			// If the abstract type was already bound in this container, we will 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 ($bound) {
				$this->rebound($abstract);
			}
		}