前言
阅读了一段时间的laravel源码,现将一个成果做一个输出。主要是围绕laavel生命周期展开。
文章目录
1.加载composer
2.创建app容器和绑定内核到app容器中
代码如下(示例):
$app = require_once __DIR__.'/../bootstrap/app.php';
2.1 创建app容器
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
public function __construct($basePath = null)
{
//设置基本路径
if ($basePath) {
$this->setBasePath($basePath);
}
//基本注册绑定到容器中
$this->registerBaseBindings();
//3个服务(events/logs/route)绑定到容器中
$this->registerBaseServiceProviders();
//为核心类设置别名
$this->registerCoreContainerAliases();
}
2.2 内核绑定app容器
//将http内核绑定到app容器中
$app->singleton(
Illuminate\Contracts\Http\Kernel::class,
App\Http\Kernel::class
);
//将console内核绑定到app容器中
$app->singleton(
Illuminate\Contracts\Console\Kernel::class,
App\Console\Kernel::class
);
//绑定异常处理
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);
3.解析内核
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
public function __construct(Application $app, Router $router)
{
//app容器
$this->app = $app;
//路由器
$this->router = $router;
$router->middlewarePriority = $this->middlewarePriority;
//中间件数组 封装为一个数组
foreach ($this->middlewareGroups as $key => $middleware) {
$router->middlewareGroup($key, $middleware);
}
//路由中间件 封装为一个数组
foreach ($this->routeMiddleware as $key => $middleware) {
$router->aliasMiddleware($key, $middleware);
}
}
public function middlewareGroup($name, array $middleware)
{
$this->middlewareGroups[$name] = $middleware;
return $this;
}
foreach ($this->routeMiddleware as $key => $middleware) {
$router->aliasMiddleware($key, $middleware);
}
4.处理http请求
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
4.1 获取http请求实例
//
public static function capture()
{
static::enableHttpMethodParameterOverride();
//从symfony里获取一个请求实例,创建一个基本的请求
return static::createFromBase(SymfonyRequest::createFromGlobals());
}
//symfony实例获取一个laravel请求报文
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;
}
4.1.1 symfony组件处理请求参数
public static function createFromGlobals()
{
$request = self::createRequestFromFactory($_GET, $_POST, [], $_COOKIE, $_FILES, $_SERVER);
if (0 === strpos($request->headers->get('CONTENT_TYPE', ''), 'application/x-www-form-urlencoded')
&& \in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), ['PUT', 'DELETE', 'PATCH'])
) {
parse_str($request->getContent(), $data);
$request->request = new ParameterBag($data);
}
return $request;
}
//实例化当前类,把php预定义变量传入
private static function createRequestFromFactory(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null): self
{
if (self::$requestFactory) {
$request = (self::$requestFactory)($query, $request, $attributes, $cookies, $files, $server, $content);
if (!$request instanceof self) {
throw new \LogicException('The Request factory must return an instance of Symfony\Component\HttpFoundation\Request.');
}
return $request;
}
return new static($query, $request, $attributes, $cookies, $files, $server, $content);
}
//构造函数
public function __construct(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null)
{
$this->initialize($query, $request, $attributes, $cookies, $files, $server, $content);
}
//给属性赋值
public function initialize(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null)
{
$this->request = new ParameterBag($request);
$this->query = new ParameterBag($query);
$this->attributes = new ParameterBag($attributes);
$this->cookies = new ParameterBag($cookies);
$this->files = new FileBag($files);
$this->server = new ServerBag($server);
$this->headers = new HeaderBag($this->server->getHeaders());
$this->content = $content;
$this->languages = null;
$this->charsets = null;
$this->encodings = null;
$this->acceptableContentTypes = null;
$this->pathInfo = null;
$this->requestUri = null;
$this->baseUrl = null;
$this->basePath = null;
$this->method = null;
$this->format = null;
}
4.2 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;
}
protected function sendRequestThroughRouter($request)
{
//绑定请求到app容器中
$this->app->instance('request', $request);
//清除之前$request实例
Facade::clearResolvedInstance('request');
//启动引导程序
$this->bootstrap();
//管道创建(Pipeline)
return (new Pipeline($this->app))
//将请求传入管道
->send($request)
//执行中间件处理
->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
//实际处理
->then($this->dispatchToRouter());
}
4.2.1 请求在管道中的实际处理
protected function dispatchToRouter()
{
return function ($request) {
$this->app->instance('request', $request);
return $this->router->dispatch($request);
};
}
Illuminate\Routing\Router
public function dispatch(Request $request)
{
$this->currentRequest = $request;
return $this->dispatchToRoute($request);
}
public function dispatchToRoute(Request $request)
{
return $this->runRoute($request, $this->findRoute($request));
}
//根据请求报文查找匹配的路由
protected function findRoute($request)
{
$this->current = $route = $this->routes->match($request);
$this->container->instance(Route::class, $route);
return $route;
}
//通过一个实例栈运行给定的路由
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)
);
}
//返回响应结果
protected function runRouteWithinStack(Route $route, Request $request)
{
$shouldSkipMiddleware = $this->container->bound('middleware.disable') &&
$this->container->make('middleware.disable') === true;
$middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route);
return (new Pipeline($this->container))
->send($request)
->through($middleware)
->then(function ($request) use ($route) {
return $this->prepareResponse(
$request, $route->run()
);
});
}
5.发送响应
$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;
}
//设置响应头部信息
public function sendHeaders()
{
// headers have already been sent by the developer
if (headers_sent()) {
return $this;
}
// headers
foreach ($this->headers->allPreserveCaseWithoutCookies() as $name => $values) {
$replace = 0 === strcasecmp($name, 'Content-Type');
foreach ($values as $value) {
header($name.': '.$value, $replace, $this->statusCode);
}
}
// cookies
foreach ($this->headers->getCookies() as $cookie) {
header('Set-Cookie: '.$cookie, false, $this->statusCode);
}
// status
header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText), true, $this->statusCode);
return $this;
}
//设置响应主体
public function sendContent()
{
echo $this->content;
return $this;
}
6.终止程序
$kernel->terminate($request, $response);
//终止程序
public function terminate($request, $response)
{
$this->terminateMiddleware($request, $response);
$this->app->terminate();
}
//终止中间件调用
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);
}
}
}
参考:
https://segmentfault.com/a/1190000014598466#
https://learnku.com/docs/the-laravel-way/5.6/Tao-4-1/2933