0. Laravel生命周期
说明Laravel生命周期前,先简单回忆一下PHP的生命周期。
当我们请求一个PHP文件时,PHP为了完成这次请求,会发生5个阶段的生命周期切换。
MINIT: 模块初始化,即调用 php.ini 中指明的扩展的初始化函数进行初始化工作,如 mysql 扩展。
RINIT: 请求初始化,即初始化为执行本次脚本所需要的变量名称和变量值内容的符号表,如 $_SESSION变量。
HANDLE: 执行该PHP脚本。
RSHUTDOWN: 请求处理完成(Request Shutdown),按顺序调用各个模块的 RSHUTDOWN 方法,对每个变量调用 unset函数,如 unset $_SESSION 变量。
MSHUTDOWN: 关闭模块(Module Shutdown),PHP调用每个扩展的 MSHUTDOWN 方法,这是各个模块最后一次释放内存的机会, 这意味着没有下一个请求了。
小结: PHP是一种脚本语言,所有的变量只会在这一次请求中生效,下次请求之时已被重置,而不像Java静态变量拥有全局作用。
Laravel 的生命周期从public\index.php开始,从public\index.php结束。具体来讲可以分成4个步骤:
1 | /** |
过程如下:
1. 程序启动准备
程序入口在 index.php 中
1 | require __DIR__.'/../vendor/autoload.php'; |
创建服务容器实例
服务容器的创建在 bootstrap\app.php
中进行.
1 | $app = new Illuminate\Foundation\Application( |
1.1 容器基础配置
容器 Application
的构造函数:
1 | public function __construct($basePath = null) |
构造函数 主要完成以下基本配置:
- 目录路径(绑定到容器中, 并提供类方法获取子目录)
1 | public function setBasePath($basePath) |
- 绑定容器自身
1 | protected function registerBaseBindings() |
- 基础服务注册( Event, Log, Route)
1 | protected function registerBaseServiceProviders() |
- 别名注册
多个接口名 对应一个简短别名, 后续在注册服务时只需绑定到别名上即可 (而不必绑定到具体接口名)
1 | public function registerCoreContainerAliases() |
1.2 核心类绑定
1 | $app->singleton( |
绑定重要接口:
- Http 核心类
- 命令行 核心类
- 异常处理类
1.3 实例化Http核心类
1 | $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); |
Http 核心类的构造函数
1 | public function __construct(Application $app, Router $router) |
上述过程主要做的事是将中间件赋值给路由
- 中间件顺序优先级列表
- 中间件组
- 中间件别名
核心类 app/Http/Kernel.php
1 |
|
2. 请求实例化
以处理 Http 请求为例
index.php
入口文件
1 | $response = $kernel->handle( |
请求是通过 Illuminate\Http\Request::capture()
实例化的, 主要是将请求信息以对象形式表现出来
3.请求处理
入口文件:
1 | $response = $kernel->handle( |
$kernel->handle(...)
处理请求过程
Illuminate\Foundation\Http\Kernel
1 | public function handle($request) |
实际处理请求逻辑主要在 sendRequestThroughRouter
方法中, 它主要做了:
核心类的初始化
经由中间件过滤后将请求最终交由
Router
处理
对于 Http 请求处理, 中间件包括:
1
2
3
4
5
6
7
8
9
10
11
12
13 protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
];
该中间件数组定义在 Http 核心类中, 同时在核心类的构造函数中传递给 Router 类
3.1 请求处理环境初始化
核心类的初始化 bootstrap()
1 | protected $bootstrappers = [ |
在服务容器 Application
类中
1 | public function bootstrapWith(array $bootstrappers) |
该步骤主要是主要是对核心类中定义的 $bootstrappers
数组元素(引导类)初始化.
bootstrap 过程具体是在服务容器来中进行, 由核心类调用并传入待初始化的类
Http 核心类默认包含以下 6 个启动服务:
- 环境监测
\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class
从 .env
文件中解析环境变量到 getevn()
, $_ENV
, $_SERVER
, 依赖 vlucas/phpdotenv
扩展包
- 配置加载
\Illuminate\Foundation\Bootstrap\LoadConfiguration::class
载入 config
目录下所有 php 配置文件, 并将生成的配置存储类绑定到服务容器 $app['config']
同时配置时区及 多字节格式(utf8)
- 异常处理
\Illuminate\Foundation\Bootstrap\HandleExceptions::class
报告所有错误 error_report(E_ALL)
提供对未捕获的异常, 错误的全局处理 set_error_handler
, set_exception_handler
, register_shutdown_function
- 外观注册
\Illuminate\Foundation\Bootstrap\RegisterFacades::class
从 app.aliases
中读取外观配置数组
1 | 'aliases' => [ |
使用 spl_autoload_register(...)
处理类加载, 配合 class_alias()
提供类的别名调用
Facade外观类基类依赖
__callStatic` 调用方法( 使用服务容器实例化对应类)
- 服务提供者注册
\Illuminate\Foundation\Bootstrap\RegisterProviders::class
从 app.providers
中读取所有服务提供者
1 | 'providers' => [ |
服务提供者经过解析后分为 3 种类型的服务提供者:
- eager 类型
马上调用 register
注册
- deferred 类型
记录下来, 当服务容器解析对应服务时, 才注册对应的服务提供者
- when 类型
记录下来, 当对应 event 触发时在注册对应服务提供者
- 启动提供者
\Illuminate\Foundation\Bootstrap\BootProviders::class
调用服务容器的 boot()
方法, 依次调用在服务容器中 register
的所有服务提供者的 boot()
方法
3.2 路由处理请求
在内核处理请求, 将请求实例通过中间件处理后, 将请求的处理交给路由 Router 进行控制器的分发.
Http Kernel
1 | protected function dispatchToRouter() |
路由表存储结构说明
Illuminate\Routing\Route
存储单条路由
Illuminate\Routing\RouteCollection
保存所有 Route
实例, 形成路由表
Illuminate\Routing\Router
类实例持有 RouteCollection
路由表实例.
即, 一个 Router
持有一个 RouteCollection
, 而 RouteCollection
拥有 N 个 Route
在 Router
中对请求的处理同样经过一系列的 路由中间件
1 | # 路由处理请求的入库 |
route
的 run()
方法最终将请求转给 Illuminate\Routing\ControllerDispatcher::dispatch
处理
1 | public function dispatch(Route $route, $controller, $method) |
剩下的事情就是 Controller控制器 的事了.
3.3 处理返回的 Response
在 Router
中有一个方法, 用于对返回的 $response
进行处理
1 | public function prepareResponse($request, $response) |
上述过程中, 在返回 $response
之前进行了最后的处理 $response->prepare($request)
该过程是在 Symfony\Component\HttpFoundation\Response::prepare()
中进行
对响应的封装是通过
Illuminate\Http\Response
类完成, 该类底层是 Symfony 框架的 Response 类
即, Symfony\Component\HttpFoundation\Response
1 | public function prepare(Request $request) |
4. 响应发送和程序终止
4.1 响应的发送
在 index.php
入口文件的最后是将响应返回给客户端
$response->send();
1 | Symfony\Component\HttpFoundation\Response |
4.2 请求中止
在 index.php
入口文件的最后:
\$kernel->terminate( \$request, \$response );
依旧以 Http Kernel 为例:
1 | public function terminate($request, $response) |
此处的中间件指的是定义在 Kernel 中的 $middleware
中间件数组列表, 不包含 路由中间件.
Laravel 5.1 注: 默认只有会话中间件包含 terminate() 函数
Application
服务容器的中止处理函数
1 | public function terminate() |