thinkphp6执⾏流程(⼀)
项⽬⽬录相对为tp6
请求被统⼀转发到⼊⼝⽂件(⼊⼝⽂件地址为 tp6/index.php)
1.⼊⼝⽂件引⼊了composer⾃动载⼊⽂件类库
<php?
namespace think;
require __DIR__ . '/../vendor/autoload.php';
(⽂件地址为 tp6/vendor/autoload.php')
2.实例化 think\App 对象赋值给$app
<?php
$app = new App();
(App类⽂件地址为 tp6/vendor/topthink/framework/src/think/App.php')
执⾏App类中的__construct构造⽅法
<?php
public function __construct(string $rootPath = '')
{
// 框架类库⽬录
$this->thinkPath = dirname(__DIR__) . DIRECTORY_SEPARATOR;
// 项⽬根⽬录
$this->rootPath = $rootPath ? rtrim($rootPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : $this->getDefaultRootPath(); // 应⽤⽬录
$this->appPath = $this->rootPath . 'app' . DIRECTORY_SEPARATOR;
// 项⽬缓存⽬录
$this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR;
// 加载服务provide容器
if (is_file($this->appPath . 'provider.php')) {
// 执⾏ Container\bind()⽅法绑定类、闭包、实例、接⼝
$this->bind(include $this->appPath . 'provider.php');
}
// 设置⼀个容器实例
static::setInstance($this);
// 绑定类的实例到容器
$this->instance('app', $this);
$this->instance('think\Container', $this);
}
其中在属性$bind中已经有了⼀些框架类的别名与实现的映射数组
此时$app因为是继承了Container类,所以$app实际也是⼀个容器
3.通过$app类调⽤http类(web管理类)
$http = $app->http;
3.0 引⽤http类的过程如下:
(http类⽂件地址为 tp6/vendor/topthink/framework/src/think/Http.php')
3.1 ⾸先App中不存在http⽅法,但是在容器类中存在魔术⽅法__get,会触发该魔术⽅法
public function __get($name)
{
return $this->get($name);
}
get⽅法从app应⽤容器中获取http对象实例
<php?
/**
* 获取容器中的对象实例
* @access public
* @param string $abstract 类名或者标识
* @return object
*/
public function get($abstract)
{
if ($this->has($abstract)) {
return $this->make($abstract);
}
throw new ClassNotFoundException('class not exists: ' . $abstract, $abstract);
}
3.2 通过app应⽤容器中的make⽅法进⾏类的实例,以及执⾏instances⽅法将实例化的http类绑定到容器数组对象中<?php
/**
* 创建类的实例已经存在则直接获取
* @access public
* @param string $abstract 类名或者标识
* @param array $vars 变量
* @param bool $newInstance 是否每次创建新的实例
* @return mixed
*/
public function make(string $abstract, array $vars = [], bool $newInstance = false)
{
$abstract = $this->getAlias($abstract);
if (isset($this->instances[$abstract]) && !$newInstance) {
return $this->instances[$abstract];
}
if (isset($this->bind[$abstract]) && $this->bind[$abstract] instanceof Closure) {
$object = $this->invokeFunction($this->bind[$abstract], $vars);
} else {
$object = $this->invokeClass($abstract, $vars);
}
if (!$newInstance) {
$this->instances[$abstract] = $object;
}
return $object;
}
返回http对象实例到调⽤处第3步开始的地⽅
4 http对象执⾏run⽅法,应⽤程序的执⾏开始
<?php
/
**
* 执⾏应⽤程序
* @access public
* @param Request|null $request
* @return Response
*/
public function run(Request $request = null): Response
{
//⾃动创建request对象
$request = $request ?? $this->app->make('request', [], true);
// 绑定request类的实例化对象到容器中
$this->app->instance('request', $request);
// 执⾏应⽤程序返回response类
$response = $this->runWithRequest($request);
} catch (Throwable $e) {
$this->reportException($e);
$response = $this->renderException($request, $e);
}
return $response;
}
4.1 run ⽅法中⾸先创建Request类,执⾏instances⽅法将实例化的Request类绑定到容器数组对象中,标识为request
然后进⾏路由调度,执⾏ app容器中runWithRequest⽅法
/**
* 执⾏应⽤程序
* @param Request $request
* @return mixed
*/
protected function runWithRequest(Request $request)
{
// 初始化app应⽤程序
$this->initialize();
// 加载全局中间件
$this->loadMiddleware();
/
/ 监听HttpRun
$this->app->event->trigger(HttpRun::class);
// 中间件调度
return $this->app->middleware->pipeline()
->send($request)
->then(function ($request) {
return $this->dispatchToRoute($request);
});
}
4.2然后在在http类中runWithRequest⽅法中执⾏了dispatchToRoute 讲请求分发到路由
(dispatchToRoute 类⽅法的⽂件地址为 tp6/vendor/topthink/framework/src/think/Route.php')
/
/ 分发请求到路由
<?php
protected function dispatchToRoute($request)
{
// 是否启⽤路由, 默认启⽤路由
$withRoute = $this->app->config->get('app.with_route', true) ? function () {
$this->loadRoutes();
} : null;
// 执⾏路由调度
return $this->app->route->dispatch($request, $withRoute);
}
4.3 在http类中dispatchToRoute 通过app容器获取了route实例,并调⽤了route实例中的dispatch⽅法
<?php
/**
* 路由调度
* @param Request $request
* @param Closure|bool $withRoute
* @return Response
*/
public function dispatch(Request $request, $withRoute = true)
{
$this->request = $request;
$this->host = $this->request->host(true);
$this->init();
if ($withRoute) {
// 加载路由设置
if ($withRoute instanceof Closure) {
$withRoute();
}
// 检查路由
$dispatch = $this->check();
} else {
// 如果没有路由,则使⽤默认url解析
$dispatch = $this->url($this->path());
}
// $dispatch 为think\route\dispatch\Controller 的实例化中的初始化,提取控制名称以及操作名称
// 1, 通过最终think\route\Rule::dispatch来确路由调度的最终执⾏动作
$dispatch->init($this->app);
return $this->app->middleware->pipeline('route')
->send($request)
->then(function () use ($dispatch) {
// 执⾏动作⽅法
return $dispatch->run();
});
}
4.4 在route类中的dispatch中执⾏了run⽅法,
(run 类⽅法的⽂件地址为 tp6/vendor/topthink/framework/src/think/route/Dispatch.php')
<?php
/**
* 执⾏路由调度
* @access public
* @return mixed
*/
public function run(): Response
{
if ($this->rule instanceof RuleItem && $this->request->method() == 'OPTIONS' && $this->rule->isAutoOptions()) {
$rules = $this->rule->getRouter()->getRule($this->rule->getRule());
$allow = [];
foreach ($rules as $item) {
$allow[] = strtoupper($item->getMethod());
}
return Response::create('', 'html', 204)->header(['Allow' => implode(', ', $allow)]);
}
// 此处调⽤的$this类,由调⽤者确定, 可能为url, callback, 或者controller
// $data 为返回的response 类
$data = $this->exec();
return $this->autoResponse($data);
}
4.5 run⽅法调⽤了exec
(此处调⽤的exec的类⽅法所在的⽂件,由调⽤者确定, 可能为url, callback, 或者controller, exec 类⽅法的⽂件地址为 tp6/vendor/topthink/framework/src/think/route/dispatch/Callback.php|Controller.php')
在exec⽅法中最终返回了data数据
4.6 然后调⽤了autoResponse⽅法,并传递4.5返回的data数据
(autoResponse 类⽅法的⽂件地址为 tp6/vendor/topthink/framework/src/think/route/Dispatch.php')
<?php
protected function autoResponse($data): Response
{
if ($data instanceof Response) {
$response = $data;
} elseif (!is_null($data)) {
// 默认⾃动识别响应输出类型
$type = $this->request->isJson() ? 'json' : 'html';
$response = Response::create($data, $type);
} else {
$data = ob_get_clean();
$content = false === $data ? '' : $data;
$status = '' === $content && $this->request->isJson() ? 204 : 200;
// 创建response类返回,使⽤html
$response = Response::create($content, 'html', $status);
}
return $response;
}
4.7 autoResponse ⽅法中执⾏了 Response::create⽅法
最终⽅法返回了response对象;
(Response::create 类⽅法的⽂件地址为 tp6/vendor/topthink/framework/src/think/Response.php') <?php
/**
* 创建Response对象
* @access public
* @param mixed $data 输出数据
* @param string $type 输出类型
* @param int $code 状态码
* @return Response
*/
public static function create($data = '', string $type = 'html', int $code = 200): Response
{
$class = false !== strpos($type, '\\') ? $type : '\\think\\response\\' . ucfirst(strtolower($type));
return Container::getInstance()->invokeClass($class, [$data, $code]);
}
php实例化后获取子类名称4.8 最终返回了 response Html类的对象实例
5 执⾏run⽅法
$response = $http->run();
6 response 执⾏send输出数据的操作;
(Html 类⽂件所在地址为 tp6/vendor/topthink/framework/src/think/response/Html.php )
6.1 执⾏send⽅法
(send⽅法类⽂件所在地址为 tp6/vendor/topthink/framework/src/think/Response.php ) $response->send();
<?php
/**
* 发送数据到客户端
* @access public
* @return void
* @throws \InvalidArgumentException
*/
public function send(): void
{
// 处理输出数据
$data = $this->getContent();
if (!headers_sent() && !empty($this->header)) {
// 发送状态码
http_response_code($this->code);
// 发送头部信息
foreach ($this->header as $name => $val) {
header($name . (!is_null($val) ? ':' . $val : ''));
}
}
if ($this->cookie) {
$this->cookie->save();
}
$this->sendData($data);
if (function_exists('fastcgi_finish_request')) {
// 提⾼页⾯响应
fastcgi_finish_request();
}
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论