thinkphp请求的处理流程
这里我们使用5.0的版本做介绍,thinkphp的git: https://github.com/top-think/think.git 看最新版本已经到6.0了,更新的很快,但核心没有太大区别。
首先看入口文件 index.php,代码如下
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <[email protected]>
// +----------------------------------------------------------------------
namespace think;
// ThinkPHP 引导文件
// 1. 加载基础文件
require __DIR__ . '/base.php';
// 2. 执行应用
App::run()->send();
加载了base.php,我们打开base.php文件会发现,除了定义一些全局变量之外,只有三行逻辑代码
// 注册自动加载
\think\Loader::register();
// 注册错误和异常处理机制
\think\Error::register();
// 加载惯例配置文件
\think\Config::set(include THINK_PATH . 'convention' . EXT);
而这三处代码,分别是注册自动加载,注册错误和异常处理机制,加载配置文件。这些我们可以先不用管,因为与请求并不直接相关,继续看App::run->send()
其中路由检测这部分,通过加载配置文件,对请求的地址串映射到对应的方法,其中==self::exec($dispath, $config);==这个方法中的dispath是由路由检测返回的,用于查找到Controller及Action.
在处理返回数据中,使用到了Response这个类,根据返回类型不同去实例化不同的子类,default_ajax_return, default_return_type,在我使用的版本中有Jsonp, Json, Redirect, View, Xml这几个类,都是从Response继承来的。
处理返回数据的时候有这么几行代码
App.php function run()
// 输出数据到客户端
if ($data instanceof Response) {
$response = $data;
} elseif (!is_null($data)) {
// 默认自动识别响应输出类型
$type = $request->isAjax() ?
Config::get('default_ajax_return') :
Config::get('default_return_type');
$response = Response::create($data, $type);
} else {
$response = Response::create();
}
Response.php create()
/**
* 创建Response对象
* @access public
* @param mixed $data 输出数据
* @param string $type 输出类型
* @param int $code
* @param array $header
* @param array $options 输出参数
* @return Response|JsonResponse|ViewResponse|XmlResponse|RedirectResponse|JsonpResponse
*/
public static function create($data = '', $type = '', $code = 200, array $header = [], $options = [])
{
$class = false !== strpos($type, '\\') ? $type : '\\think\\response\\' . ucfirst(strtolower($type));
if (class_exists($class)) {
$response = new $class($data, $code, $header, $options);
} else {
$response = new static($data, $code, $header, $options);
}
return $response;
}
/**
* 发送数据到客户端
* @access public
* @return mixed
* @throws \InvalidArgumentException
*/
public function send()
{
// 监听response_send
Hook::listen('response_send', $this);
// 处理输出数据
$data = $this->getContent();
// Trace调试注入
if (Env::get('app_trace', Config::get('app_trace'))) {
Debug::inject($this, $data);
}
if (200 == $this->code) {
$cache = Request::instance()->getCache();
if ($cache) {
$this->header['Cache-Control'] = 'max-age=' . $cache[1] . ',must-revalidate';
$this->header['Last-Modified'] = gmdate('D, d M Y H:i:s') . ' GMT';
$this->header['Expires'] = gmdate('D, d M Y H:i:s', $_SERVER['REQUEST_TIME'] + $cache[1]) . ' GMT';
Cache::tag($cache[2])->set($cache[0], [$data, $this->header], $cache[1]);
}
}
if (!headers_sent() && !empty($this->header)) {
// 发送状态码
http_response_code($this->code);
// 发送头部信息
foreach ($this->header as $name => $val) {
if (is_null($val)) {
header($name);
} else {
header($name . ':' . $val);
}
}
}
//====注意这里是输出部分====
echo $data;
if (function_exists('fastcgi_finish_request')) {
// 提高页面响应
fastcgi_finish_request();
}
// 监听response_end
Hook::listen('response_end', $this);
// 清空当次请求有效的数据
if (!($this instanceof RedirectResponse)) {
Session::flush();
}
}
/**
* 获取输出数据
* @return mixed
*/
public function getContent()
{
if (null == $this->content) {
$content = $this->output($this->data);
if (null !== $content && !is_string($content) && !is_numeric($content) && !is_callable([
$content,
'__toString',
])
) {
throw new \InvalidArgumentException(sprintf('variable type error: %s', gettype($content)));
}
$this->content = (string) $content;
}
return $this->content;
}
如果要返回指定格式的web内容,我们只需要从Response继承出子类,重写output函数即可。
到这里请求的处理流程就梳理完了,介绍这些内容,有助于我们后面讲解使用php进行动态数据加载,如果对处理流程不清楚的话,理解起来会有些吃力。
下期内容
使用php实现数据动态加载,以一个网站评论模块为例讲解,涉及内容较多,数据库,缓存,登录认证,验证码生成等等,需要的基本数据表有: user, site, thread, comment。基本结构如下图:
user
site
thread
comment
下一篇将详细介绍评论系统的构建