$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

以laravel 框架中入口文件的一行代码进行分析。由于Illuminate\Contracts\Http\Kernel::class  绑定的具体的类为App\Http\Kernel ,所以其实就是对App\Http\Kernel的解析,结合http://blog.csdn.net/qq_16877261/article/details/78053512  这篇文章,我们直接从容器中 build函数进行分析。

/**
 * Instantiate a concrete instance of the given type.
 *    实例化一个具体的对象
 * @param  string  $concrete
 * @return mixed
 *
 * @throws \Illuminate\Contracts\Container\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 ($concrete instanceof Closure) {
        return $concrete($this);
    }

    $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()) {
        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 (is_null($constructor)) {
        array_pop($this->buildStack);

        return new $concrete;
    }
    $dependencies = $constructor->getParameters();

    if($concrete == 'App\Http\Kernel'){
        
        dd($dependencies);
        
    }

    // 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.
    //解析构造函数中的变量,如果有依赖类,也会自动解析。
    $instances = $this->resolveDependencies(
        $dependencies
    );
    array_pop($this->buildStack);
    //从给出的参数创建一个新的类实例
    return $reflector->newInstanceArgs($instances);
}

打印$dependencies 结果如下:

这里利用了PHP的反射类获取 所要实例化类的构造函数的参数。在laravel中,构造函数中一般会使用依赖注入,所以在获取的参数中包含有依赖的类,应该如何处理呢?

laravel 中 在resolveDependencies函数进行了处理。

/**
 * Resolve all of the dependencies from the ReflectionParameters.
 *
 * @param  array $dependencies
 * @return array
 */
protected function resolveDependencies(array $dependencies)
{
    $results = [];

    foreach ($dependencies as $dependency) {
        // 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.
        $results[] = is_null($class = $dependency->getClass())
            ? $this->resolvePrimitive($dependency)
            : $this->resolveClass($dependency);//参数 如果依赖的是一个类,会执行这个
    }                                          //函数,解析依赖的类。这就是依赖注入

    return $results;                          //原理,发现很简单啊大笑
}
最后根据给出的参数实例化类。在本例中就是App\Http\Kernel。于是我们就去查看这个类,发现这个类只有三个属性数组,当然你不知道它们是用来做什么的,于是查看父类

Illuminate\Foundation\Http\Kernel 。父类的构造函数中没有特别的操作(只是进行一些属性的操作和一些中间件的注册),可以自行查看。至此该类的实例化完成。

于是我们接着查看入口文件

$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

所以接着查看Illuminate\Foundation\Http\Kernel中的handle函数。

public function handle($request)
{
    try {
        $request->enableHttpMethodParameterOverride();

        $response = $this->sendRequestThroughRouter($request);
    } catch (Exception $e) {
        $this->reportException($e);

        $response = $this->renderException($request, $e);
    } catch (Throwable $e) {
        $this->reportException($e = new FatalThrowableError($e));

        $response = $this->renderException($request, $e);
    }

    event(new Events\RequestHandled($request, $response));

    return $response;
}

查看这个函数发现我只需要看sendRequestThroughRouter 这个函数就可以了。

 protected function sendRequestThroughRouter($request)
{      // 实例化一个已经存在的实例
 $this->app->instance('request', $request);

    Facade::clearResolvedInstance('request');

    $this->bootstrap();

    return (new Pipeline($this->app))
        ->send($request)
        ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
        ->then($this->dispatchToRouter());
}
我们查看bootstrap,又去查看bootstrapWith 函数如下:

public function bootstrapWith(array $bootstrappers)
{
    $this->hasBeenBootstrapped = true;
    //dd($this['events']);
    foreach ($bootstrappers as $bootstrapper) {
        //events 对应绑定的类为 Dispatcher类
        $this['events']->fire('bootstrapping: '.$bootstrapper, [$this]);
//     从容器解析引导类,并且执行引导类的bootstrap方法
$this->make($bootstrapper)->bootstrap($this); $this['events']->fire('bootstrapped: '.$bootstrapper, [$this]); }}
又查看fire函数如下:

public function fire($event, $payload = [], $halt = false)
{
    return $this->dispatch($event, $payload, $halt);
}
最终查看dispatch 函数如下:

public function dispatch($event, $payload = [], $halt = false)
{
    // When the given "event" is actually an object we will assume it is an event
    // object and use the class as the event name and this event itself as the
    // payload to the handler, which makes object based events quite simple.
    list($event, $payload) = $this->parseEventAndPayload(
        $event, $payload
    );
    //引导程序不执行这部分
    if ($this->shouldBroadcast($payload)) {
        $this->broadcastEvent($payload[0]);
    }
    $responses = [];
   // dd($this->getListeners($event));

    //引导程序不执行这部分
    foreach ($this->getListeners($event) as $listener) {
        $response = $listener($event, $payload);
        // If a response is returned from the listener and event halting is enabled
        // we will just return this response, and not call the rest of the event
        // listeners. Otherwise we will add the response on the response list.
        if (! is_null($response) && $halt) {
            return $response;
        }
        // If a boolean false is returned from a listener, we will stop propagating
        // the event to any further listeners down in the chain, else we keep on
        // looping through the listeners and firing every one in our sequence.
        if ($response === false) {
            break;
        }

        $responses[] = $response;
    }

    return $halt ? null : $responses;
}
发现引导类第一次执行后返回是一个空数组。

于是    $this->bootstrap(); 这句其实就是执行对应引导类的bootstrap方法。

最后关于管道的理解请参考

http://www.jianshu.com/p/3c2791a525d0












zheyu方法

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐