Laravel 号称为艺术而生的web 框架, 该框架通过compser 管理依赖,实现了mvc,orm,cache,router,等常用web开发功能。 其代码优雅简洁。要想理解很好的理解一个框架其生命周期是不可逾越的, 当你真正理解了框架的生命周期, 你才能明白一个http请求是如何被处理的。
一切得开始 index.php
index.php 是框架的唯一入口文件,其代码如下
<?php
require __DIR__.'/../bootstrap/autoload.php';
$app = require_once __DIR__.'/../bootstrap/app.php';
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
$response->send();
$kernel->terminate($request, $response);
index.php 完成了如下工作
1、autoload.php 到的导入,autoload 是一个文件加载管理器,由composer 提供,完成框架中所有需要用到的文件的自动载入。
2、引入app.php 完成Application的创建,并载入。
3、由app应用创建http kernel 。
4、发生request 到http kernel,返回response 。
5、将respose 的响应send 到客户端。
6、一些其他处理
以上就是index.php 完成的全部工作, 该几步工作也概括的、清晰的描述出了从一个请求到响应的概括步骤, 就这一点而言比有些框架 直接 new application 然后run 要具有高度的抽象概括性,用最少的抽象代码描述了http请求的流程。
<?php
require __DIR__.'/../bootstrap/autoload.php';
$app = new Application();
$app->run();
Laravel 框架入口index.php 每个步骤的详细介绍
1、自动加载autoload.php
自动加载在lavarel中用的是composer 提供的免费的loader, 在这里不打算详细介绍, 其核心实现是通过spl_autoload_register() 来完成的。 感兴趣的同学可以研究其源码。
2、Application 的初始化
Application 是Laravel 框架各个功能组件的调度者,其本身就是一个服务容器,Laravel 框架通过依赖注入管理各组件的依赖关系。其基本服务会注册到Application中。Application的实例化时运行的核心代码如下。
<?php
class Application extends Container implements ApplicationContract, HttpKernelInterfac
{
... 此处略去若干字
public function __construct($basePath = null)
{
if ($basePath) {
$this->setBasePath($basePath);
}
$this->registerBaseBindings();
$this->registerBaseServiceProviders();
$this->registerCoreContainerAliases();
}
... 此处略去若干字
}
可以看到Application 继承Container类,从构造函数中可以 看出主要完成了如下工作。
1、设置项目path
2、初始化自身
3、注册基础服务
4、注册核心服务的别名
接下来神奇的事情开始了
<?php
$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
);
这些代码就是绑定具体实现到抽象定义。
3、http内核是如何创建的
http 内核的创建相对简单, 就是通过app make出来的,代码如下
<?php
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
从代码我们可以看出创建内核传入的并不是http内核的具体实现类,而是契约类或者说接口类,这样就完成了设计与实现的解耦。
面向接口编程,可以将实现和设计解构
4、requset 是如何被处理的,并返回response
requset 的处理相对来说会复杂一些,这里我们会详细介绍。从入口文件 index.php 我们可以看出http kernel 被创建后会调用其handle,调用的时候会传入request ,handle的代码如下
<?php
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;
}
看代码能找到最重要的一行也是一种能力,在不需要理解细节的情况下这个能力尤为重要, 好让我们发现那个重点。
$response = $this->sendRequestThroughRouter($request);
没错就是它。
命名的规范、表意会让阅读你代码的人感谢你的用心。
从名字我们可以看出, 通过router 发送request 请求就得到了response的返回, 就是说我们将请求在router上跑一边就到了了response。
5、结束这一切吧, send回去。
当然最后我们要给请求一个交代,这叫有始有终,有因有果
在入口文件 index.php 的体现的是
<?php
$response->send();
具体实现是以下代码
public function send()
{
$this->sendHeaders();
$this->sendContent();
if (function_exists('fastcgi_finish_request')) {
fastcgi_finish_request();
} elseif ('cli' !== PHP_SAPI) {
static::closeOutputBuffers(0, true);
}
return $this;
}