代码:
<?php
//laravel 启动时间
define('LARAVEL_START', microtime(true));
/*
|--------------------------------------------------------------------------
| Register The Auto Loader
加载项目依赖
|
*/
require __DIR__.'/../vendor/autoload.php';
/*
|--------------------------------------------------------------------------
| Turn On The Lights
|--------------------------------------------------------------------------
|
创建laravel应用实例
|
*/
$app = require_once __DIR__.'/../bootstrap/app.php';
/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client's browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
通过实例出来的内核来接收请求并响应
|
*/
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
//结束请求,进行回调
$response->send();
//终止程序
$kernel->terminate($request, $response);
2.2创建laravel应用实例
创建应用实例(服务容器),由 bootstrap/app.php 文件里的引导程序完成,创建服务容器的过程就是应用初始化的过程,项目初始化过程包括(注册项目基础服务,注册项目服务提供者别名,注册目录路径等在内的一系列注册工作
<?php
//1:创建应用实例
$app = new Illuminate\Foundation\Application(
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
//2:完成内核绑定 ,待后续使用时实例
$app->singleton(
Illuminate\Contracts\Http\Kernel::class,
App\Http\Kernel::class
);
$app->singleton(
Illuminate\Contracts\Console\Kernel::class,
App\Console\Kernel::class
);
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);
return $app;
2.2.1 创建应用实例
创建应用实例 就是实例化 Illuminate\Foundation\Application 这个类 这个实例我们可称作app容器,在完成实例化时 执行构造函数 注册应用的基础路径并将路径绑定到容器中,注册基础服务提供者到容器中,注册核心容器别名到容器中
<?php
//文件路径 Illuminate\Foundation\Application
public function __construct($basePath = null)
{
if ($basePath) {
$this->setBasePath($basePath);
}
$this->registerBaseBindings();
$this->registerBaseServiceProviders();
$this->registerCoreContainerAliases();
}
2.2.2 内核绑定
laravel 根据http请求的运行环境的不同 将请求发送至相应的内核:http内核 或者console内核. 二者的作用都是接受请求,然后返回一个响应
以http内核为例,http内核(app/Http/Kernel.php ) 继承Illuminate\Foundation\Http\Kernel类
http内核 定义了中间件,而Illuminate\Foundation\Http\Kernel类 定义了 $bootstrappers 引导程序数组
中间件:提供了一种方便的机制来过滤进入应用的http请求
引导程序:包括完成环境监测,配置加载,服务提供者注册,facades注册,异常处理器注册,启动服务这个六个领导程序
2.2.3注册异常处理
项目的异常处理有App\Exceptions\Handler::class 完成
2.3接受请求并返还响应
完成创建app容器后 就进入接受请求并响应的过程
接收请求并响应代码如下
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client's browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
|
*/
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
$response->send();
2.3.1解析内核实例
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
查看Illuminate\Contracts\Http\Kernel 内核的构造方法
/**接收app容器和路由器两个参数
在实例化内核时,构造函数内将http内核内定义的中间件数组注册到路由器,注册完后就可以在实际处理http请求前调用这些中间件 实现过滤的目的
* Create a new HTTP kernel instance.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @param \Illuminate\Routing\Router $router
* @return void
*/
public function __construct(Application $app, Router $router)
{
$this->app = $app; //容器
$this->router = $router; //路由器
$router->middlewarePriority = $this->middlewarePriority; // App\Http\Kernel 该类中定义的中间件数组
foreach ($this->middlewareGroups as $key => $middleware) { //将中间件注册到路由器中
$router->middlewareGroup($key, $middleware);
}
foreach ($this->routeMiddleware as $key => $middleware) {
$router->aliasMiddleware($key, $middleware);
}
}
2.3.2处理http请求
//处理请求
$response = $kernel->handle(
//创建请求实例
$request = Illuminate\Http\Request::capture()
);
2.3.2.1 创建请求实例
Illuminate\Http\Request::capture() 通过该静态方法 通过symfony实例创建一个laravel请求实例,这样可以获取到用户请求报文的相关信息
//代码路径 Illuminate\Http\Request
public static function capture()
{
static::enableHttpMethodParameterOverride();
return static::createFromBase(SymfonyRequest::createFromGlobals());
}
/**
* Create an Illuminate request from a Symfony instance.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* @return \Illuminate\Http\Request
*/
public static function createFromBase(SymfonyRequest $request)
{
if ($request instanceof static) {
return $request;
}
$content = $request->content;
$request = (new static)->duplicate(
$request->query->all(), $request->request->all(), $request->attributes->all(),
$request->cookies->all(), $request->files->all(), $request->server->all()
);
$request->content = $content;
$request->request = $request->getInputSource();
return $request;
}
具体关于symfonyRequest https://blog.youkuaiyun.com/ahaotata/article/details/85088638
2.3.2.2 处理请求
请求发生在 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);
}
$this->app['events']->dispatch(
new Events\RequestHandled($request, $response)
);
return $response;
}
$this->sendRequestThroughRouter($request)方法代码如下
protected function sendRequestThroughRouter($request)
{
//将$request 实例注册到容器中 供后续使用
$this->app->instance('request', $request);
//删除之前的$request 实例缓存
Facade::clearResolvedInstance('request');
//启动引导程序
$this->bootstrap();
return (new Pipeline($this->app)) //创建管道
->send($request)
->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
->then($this->dispatchToRouter());
}
主要逻辑:
1,将request实例注册到容器中供后续使用
2,删除之前的request实例缓存
3,启动 引导程序
2.3.2.2.1 启动 引导程序
$this->bootstrap();
public function bootstrap()
{
if (! $this->app->hasBeenBootstrapped()) {
//调用 Illuminate\Foundation\Application 中的 bootstrapWith方法
$this->app->bootstrapWith($this->bootstrappers());
}
}
该方法实际上调用了app容器的bootstrapWith ()方法
public function bootstrapWith(array $bootstrappers)
{
$this->hasBeenBootstrapped = true;
// protected $bootstrappers = [
// \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class, 环境检测 通过DOTENV组件将。env配置文件载入到$_ENV变量中
// \Illuminate\Foundation\Bootstrap\LoadConfiguration::class, 配置加载文件
// \Illuminate\Foundation\Bootstrap\HandleExceptions::class, 异常处理
// \Illuminate\Foundation\Bootstrap\RegisterFacades::class, 注册门面 注册完后可以以别名方式访问具体的类
// \Illuminate\Foundation\Bootstrap\RegisterProviders::class, 注册服务提供者,将config/app.php文件下的providers节点的服务器提供者注册到容器中,供请求处理阶段使用
// \Illuminate\Foundation\Bootstrap\BootProviders::class, 启动服务
// ];
foreach ($bootstrappers as $bootstrapper) {
$this['events']->dispatch('bootstrapping: '.$bootstrapper, [$this]);
//解析对应的引导程序 就就是实例化 然后调用 bootstrap方法
$this->make($bootstrapper)->bootstrap($this);
$this['events']->dispatch('bootstrapped: '.$bootstrapper, [$this]);
}
}
2.3.2.2.1 发送请求到路由
完成引导程序操作后 就进去到请求处理阶段
protected function sendRequestThroughRouter($request)
{
//将$request 实例注册到容器中 供后续使用
$this->app->instance('request', $request);
//删除之前的$request 实例缓存
Facade::clearResolvedInstance('request');
//启动引导程序
$this->bootstrap();
//处理请求的逻辑
return (new Pipeline($this->app)) //创建管道
->send($request)
->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
->then($this->dispatchToRouter());
}
涉及到 管道创建 将$request传入管道,对$request执行中间件处理和实际的请求处理
$this->dispatchToRouter()该方法代码如下
protected function dispatchToRouter()
{
return function ($request) {
$this->app->instance('request', $request);
return $this->router->dispatch($request);
};
}
通过router 实例的 disptach() 方法去执行 HTTP 请求,在它的内部会完成如下处理:
- 查找对应的路由实例
- 通过一个实例栈运行给定的路由
- 运行在 routes/web.php 配置的匹配到的控制器或匿名函数
- 返回响应结果
//文件路径 Illuminate\Routing\Router
/**
* Dispatch the request to the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse
*/
public function dispatch(Request $request)
{
$this->currentRequest = $request;
return $this->dispatchToRoute($request);
}
/**
* Dispatch the request to a route and return the response.
*
* @param \Illuminate\Http\Request $request
* @return mixed
*/
public function dispatchToRoute(Request $request)
{
return $this->runRoute($request, $this->findRoute($request));
}
/**
* Find the route matching a given request.查找对应的路由实例
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Routing\Route
*/
protected function findRoute($request)
{
$this->current = $route = $this->routes->match($request);
$this->container->instance(Route::class, $route);
return $route;
}
**
* Return the response for the given route. 通过一个实例栈运行给定的路由
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Routing\Route $route
* @return mixed
*/
protected function runRoute(Request $request, Route $route)
{
$request->setRouteResolver(function () use ($route) {
return $route;
});
$this->events->dispatch(new Events\RouteMatched($route, $request));
return $this->prepareResponse($request,
$this->runRouteWithinStack($route, $request)
);
}
/**
* Run the given route within a Stack "onion" instance. 通过一个实例栈运行给定的路由
*
* @param \Illuminate\Routing\Route $route
* @param \Illuminate\Http\Request $request
* @return mixed
*/
protected function runRouteWithinStack(Route $route, Request $request)
{
$shouldSkipMiddleware = $this->container->bound('middleware.disable') &&
$this->container->make('middleware.disable') === true;
$middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route);
//4. 返回响应结果
return (new Pipeline($this->container))
->send($request)
->through($middleware)
->then(function ($request) use ($route) {
return $this->prepareResponse(
//运行在 routes/web.php 配置的匹配到的控制器或匿名函数
$request, $route->run()
);
});
}
执行 $route->run() 的方法定义在 Illuminate\Routing\Route 类中,最终执行「在 routes/web.php 配置的匹配到的控制器或匿名函数」:
public function run()
{
$this->container = $this->container ?: new Container;
try {
if ($this->isControllerAction()) {
return $this->runController();
}
return $this->runCallable();
} catch (HttpResponseException $e) {
return $e->getResponse();
}
}
这部分如果路由的实现是一个控制器,会完成控制器实例化并执行指定方法;如果是一个匿名函数则直接调用这个匿名函数。
其执行结果会通过 Illuminate\Routing\Router::prepareResponse($request, $response) 生一个响应实例并返回。
至此,Laravel 就完成了一个 HTTP 请求的请求处理。
2.4 发送响应
经过一系列 的操作http请求最终进入 发送响应值客户端$request->send()
发送响应由 Illuminate\Http\Response 父类 Symfony\Component\HttpFoundation\Response 中的 send() 方法完成。
public function send()
{
$this->sendHeaders();
$this->sendContent();
if (\function_exists('fastcgi_finish_request')) {
fastcgi_finish_request();
} elseif (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
static::closeOutputBuffers(0, true);
}
return $this;
}
2.5 终止程序
程序终止,完成终止中间件的调用
/**
* Call the terminate method on any terminable middleware.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Http\Response $response
* @return void
*/
public function terminate($request, $response)
{
$this->terminateMiddleware($request, $response);
$this->app->terminate();
}
/**
* Call the terminate method on any terminable middleware.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Http\Response $response
* @return void
*/
protected function terminateMiddleware($request, $response)
{
$middlewares = $this->app->shouldSkipMiddleware() ? [] : array_merge(
$this->gatherRouteMiddleware($request),
$this->middleware
);
foreach ($middlewares as $middleware) {
if (! is_string($middleware)) {
continue;
}
[$name] = $this->parseMiddleware($middleware);
$instance = $this->app->make($name);
if (method_exists($instance, 'terminate')) {
$instance->terminate($request, $response);
}
}
}
3总结
首先是加载自动加载autoload.php 然后 创建app容器,创建容器的时候 会 注册基础服务,注册服务提供者别名,注册目录路径等工作, 然后绑定 http内核 和console内核 异常处理器
接着解析http内核 实例化的时候调用构造方法将中间件注册到路由器 这些准备工作做完之后 开始正式接收请求
一个http请求实例 被注册到容器中,通过内核的handalI()放来 来自动 引导程序 设置环境变量,加载配置文件 注册服务提供者 注册门面 启动服务 随后请求被分发到匹配的路由,在路由中执行中间件过滤不满足校验规则的请求,通过中间件处理的请求才最终处理实际的控制器或者匿名函数生成响应结果
最后发送响应给用户,清理项目中的中间件