最近以Laravel5.5版本为例仔细研究了下Laravel的生命周期,其实还蛮有意思的,以前都是看别人的,看完就忘…
Laravel的整个生命周期总结如下图:
开始
首先从public/index.php
入口开始,可以看到里面就做了4件事。
一、定义框架的启动时间,单位毫秒 对应代码
|
|
二、注册并加载composer自动加载器,对应代码
|
|
三、获取Application应用实例,对应代码
|
|
四、运行容器,对应代码
|
|
如何获取应用实例
做的最多事情的其实就是上面的第三和第四部分。先来看下如何获取应用实例的。根据代码首先是加载的 bootstrap/app.php
文件。代码也很简单主要做了下面几个事情。
实例化
可以看到进来就是创建应用也就是Application实例对象也是容器对象。根据官方的注释可以看到:
我们要做的第一件事就是创建一个新的laravel应用实例,它连接着laravel的各个部分,同时它还是系统绑定各个部分的一个IOC容器。
这里做了最多的事情,对应代码如下,他传递进去的参数是一个基础路径
|
|
然后来看下实例化做了什么,对应文件 vendor/laravel/framework/src/Illuminate/Foundation/Application.php
的构造函数
|
|
这个构造函数主要是做了4个工作。
设置框架运行的基础路径
具体函数如下:
|
|
给容器注册基础绑定
具体代码:
|
|
注册所有的基础服务提供者
|
|
给容器(也是application实例)注册核心类别名
|
|
至此完成了实例的初始化,添加了一些基础属性等。
绑定核心接口
根据官方注释第二步需要进行核心接口的绑定。 需要注意 app是 application的实例,然后继承了Illuminate\Container\Container; 所以这里的singleton方法其实是Container里的给容器注册绑定。对应代码:
|
|
这个绑定核心接口部分做了3件事,主要是通过 singleton
方法,参数是一个抽象类,一个具体实现类。完成了HTTP内核注册,控制台注册和异常处理注册。
主要看下 vendor/laravel/framework/src/Illuminate/Container/Container.php
文件中的 bind
方法,因为在 singleton
方法中调用了 bind
.
|
|
可以看到最终这些绑定关系都放在了 Container 实例的 bindings
属性中,key是抽象类名,值是具体实现类名。
然后返回实例,对应代码: return $app;
至此完成了应用的实例化。
如何运行容器
在完成了容器的初始化后需要运行容器,在这里又需要做4件事。
从应用实例中解析出HTTP内核实例对象
主要代码是 publuc/index.php
文件中的 $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
这一行。主要看下 make
方法。在文件 vendor/laravel/framework/src/Illuminate/Foundation/Application.php
中,不过最后它又调用了父类的 make
方法,在 vendor/laravel/framework/src/Illuminate/Container/Container.php
中。最终可以看到调用的是父类的 resolve
方法。
简单说明下吧,该方法主要是从容器的实例对象中根据传入的参数抽象类名,获取到了当初绑定的对应实现类,不过是一个闭包,然后根据闭包实例化了实现类并返回。在上面的分析中 Container 实例的 bindings
属性中绑定过HTTP内核了,对应的实现类是 app/Http/Kernel.php
所以返回的 $kernel
就是这个类的实例。
调用http内核的 handle
方法处理请求
上一步已经获取了HTTP内核的实例,然后开始处理请求,对应代码
|
|
主要这里调用的 handle
方法,因为返回的kernel是 App\Http\Kernel.php
的实例,而它又继承自 vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php
所以 handle
方法其实是在父类中的。
不过处理这个前需要看下那个参数,他需要的参数是一个 request,具体应该是 Illuminate Http请求
构建Request请求
在代码 $request = Illuminate\Http\Request::capture()
中
|
|
然后来看下 SymfonyRequest::createFromGlobals()
方法干了什么
|
|
他主要就是用PHP里的超全局变量设置到了一个 vendor/symfony/http-foundation/Request.php
的实例对象中,然后返回了实例。
从Symfony实例创建Illuminate请求
回到 vendor/laravel/framework/src/Illuminate/Http/Request.php
的 createFromBase
方法。
|
|
注意看其中的 duplicate
方法,因为 当前类继承了Symfony下的http-foundation\Request 而传递进来的request刚好是http-foundation\Request的实例 所以duplicate方法也就是 http-foundation\Request 中的 duplicate
方法。其中对request实例进行了 clone
操作,并把下面的参数赋值到了一些变量属性上,重新返回了Request实例。只不过当前返回的实例已经变成 vendor/laravel/framework/src/Illuminate/Http/Request.php
的实例了。
回到handle函数
获取到request实例后,回来看下 handle
函数,其中又调用了 sendRequestThroughRouter
方法
|
|
然后就返回了一个 Illuminate\Http\Response
的 response
实例。
返回请求结果
在获取到Request的请求结果后通过 $response->send();
来输出结果。send方法在 vendor/symfony/http-foundation/Response.php
中,然后通过调用父类 vendor/symfony/http-foundation/Response.php
的 sendContent
方法,直接 echo
出了内容就算返回了。
终止应用
在返回处理结果后 通过调用 $kernel->terminate($request, $response);
来终止应用,到此结束。