Laravel Container

Container

Container是Laravel的一个类,命名为容器,在其生命周期中,表现为一个继承自它的Application类被实例化后,履行着它的各项职责,为的是IOC与良好的拓展性与复用性。下文是从源码来分析container类的几个方法和其起到的作用

Binding - 绑定

bind method

/**
 * 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)
{
    $abstract = $this->normalize($abstract);

    $concrete = $this->normalize($concrete);

    // 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 (is_array($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. After that, the concrete type to be registered as shared
    // without being forced to state their classes in both of the 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 (! $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);
    }
}

singleton method

/**
 * 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);
}

alias method

/**
 * Alias a type to a different name.
 *
 * @param  string  $abstract
 * @param  string  $alias
 * @return void
 */
public function alias($abstract, $alias)
{
    $this->aliases[$alias] = $this->normalize($abstract);
}

Resolving - 解析

make method

/**
 * Resolve the given type from the container.
 *
 * @param  string  $abstract
 * @param  array   $parameters
 * @return mixed
 */
public function make($abstract, array $parameters = [])
{
    $abstract = $this->getAlias($this->normalize($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 (isset($this->instances[$abstract])) {
        return $this->instances[$abstract];
    }

    $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.
    if ($this->isBuildable($concrete, $abstract)) {
        $object = $this->build($concrete, $parameters);
    } else {
        $object = $this->make($concrete, $parameters);
    }

    // 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.
    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 ($this->isShared($abstract)) {
        $this->instances[$abstract] = $object;
    }

    $this->fireResolvingCallbacks($abstract, $object);

    $this->resolved[$abstract] = true;

    return $object;
}

build method

/**
 * Instantiate a concrete instance of the given type.
 *
 * @param  string  $concrete
 * @param  array   $parameters
 * @return mixed
 *
 * @throws \Illuminate\Contracts\Container\BindingResolutionException
 */
public function build($concrete, array $parameters = [])
{
    // 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 ($concrete instanceof Closure) {
        return $concrete($this, $parameters);
    }

    $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 (! $reflector->isInstantiable()) {
        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);
    }

    $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 (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.
    $parameters = $this->keyParametersByArgument(
        $dependencies, $parameters
    );

    $instances = $this->getDependencies(
        $dependencies, $parameters
    );

    array_pop($this->buildStack);

    return $reflector->newInstanceArgs($instances);
}
2016-11-11 12:18 372
Comments
Write a Comment