目前很多文章已经对Laravel的执行原理做了详细介绍,这里只是为了个人做一下简单记录
首先看入口 index.php
<?php
/**
* Laravel - A PHP Framework For Web Artisans
*
* @package Laravel
* @author Taylor Otwell <taylor@laravel.com>
*/
define('LARAVEL_START', microtime(true));
/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| our application. We just need to utilize it! We'll simply require it
| into the script here so that we don't have to worry about manual
| loading any of our classes later on. It feels great to relax.
|
*/
require __DIR__ . '/../vendor/autoload.php';
/*
|--------------------------------------------------------------------------
| Turn On The Lights
|--------------------------------------------------------------------------
|
| We need to illuminate PHP development, so let us turn on the lights.
| This bootstraps the framework and gets it ready for use, then it
| will load up this application so that we can run it and send
| the responses back to the browser and delight our users.
|
*/
$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);
关键的执行函数就是 handle方法 ,但是前面的几个预处理函数,包括了整合框架的大知识点。
进入
require_once __DIR__.'/../bootstrap/app.php';
发现 $app初始化了Application对象
$app = new Illuminate\Foundation\Application(
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
紧接着有一个关键操作 singleton
$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
);
这里的单例,将抽象类绑定给了实体类
包括后面 index.php 里面马上在make方法中用到的
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
因此$kernel 得到的是 App\Http\Kernel::class 的实例对象。
继续看后面
$kernel执行handle
App\Http\Kernel::class 继承了
Illuminate\Foundation\Http\Kernel
因此执行的是
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;
}
我们关键留意
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());
}
这里的首先将 $request 注册到公共容器中
through 方法会将原本定义在 App\Http\Kernel::class 里面的 中间件
protected $middleware = [
\App\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,
//\App\Http\Middleware\Api\V1\Statistics\Common\CommonStatisticsMiddleware::class
];
成员变量注入到管道中,
->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
通过array_reduce 方法会依次将中间件中handle方法执行
最后执行 $this->dispatchToRouter();
可能有些朋友不解了
public function then(Closure $destination)
{
$pipeline = array_reduce(
array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination)
);
return $pipeline($this->passable);
}
按照array_reduce方法不是将
$this->prepareDestination($destination)
首先执行吗,这个也的确没毛病,关键是这个prepareDestination 只是作为一个预加载的作用,执行后返回的是一个后调函数,回调函数里面才是我们前面提到的$this->dispatchToRouter() , 因此它会被注入到管道的最底部,将倒序之后的中间件执行注入之后,最后得到的就是 首个中间件的
Closure 闭包方法。
public function then(Closure $destination)
{
$pipeline = array_reduce(
array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination)
);
return $pipeline($this->passable);
}
最后一步,将这个闭包执行,就可以依次执行中间件的验证,和dispatchToRouter方法了