一、 缓存参数定义
设置缓存目录
thinkphp/base.php
// 定义渲染模板文件缓存目录
defined('CACHE_PATH') or define('CACHE_PATH', RUNTIME_PATH . 'cache' . DS);
// 定义编译文件缓存目录
defined('TEMP_PATH') or define('TEMP_PATH', RUNTIME_PATH . 'temp' . DS);
设置缓存参数
application/config.php
'cache' => [
// 驱动方式
'type' => 'File',
// 缓存保存目录
'path' => CACHE_PATH,
// 缓存前缀
'prefix' => '',
// 缓存有效期 0表示永久缓存
'expire' => 0,
]
二、 输出页面
调用视图实例,展示页面
application/admin/controller/auth/Admin.php
public function index()
{
// 这里调用视图类的fetch方法,返回渲染后的模板,见解析和获取模板内容,用于输出
return $this->view->fetch();
}
解析和获取模板内容,用于输出
thinkphp/library/think/View.php
/**
* 解析和获取模板内容 用于输出
* @param string $template 模板文件名或者内容
* @param array $vars 模板输出变量
* @param array $replace 替换内容
* @param array $config 模板参数
* @param bool $renderContent 是否渲染内容
* @return string
* @throws Exception
*/
public function fetch($template = '', $vars = [], $replace = [], $config = [], $renderContent = false)
{
// 模板变量
$vars = array_merge(self::$var, $this->data, $vars);
// 页面缓存
ob_start(); // 当输出缓冲激活后,脚本将不会输出内容(除http标头外),相反需要输出的内容被存储在内部缓冲区中。
ob_implicit_flush(0); // 关闭隐式刷送,绝对(隐式)刷送将导致在每次输出调用后有一次刷送操作,以便不再需要对 flush() 的显式调用。
// 渲染输出
try {
// 使用display可以传入模板文件内容字符串$content,使用fetch是使用已设计好的模板文件
$method = $renderContent ? 'display' : 'fetch';
// 允许用户自定义模板的字符串替换
$replace = array_merge($this->replace, $replace, (array) $this->engine->config('tpl_replace_string'));
// ↓调用视图驱动thinkphp/library/think/view/driver/Think.php
$this->engine->config('tpl_replace_string', $replace);
$this->engine->$method($template, $vars, $config);
} catch (\Exception $e) {
// 清空缓冲区并关闭输出缓冲
ob_end_clean();
throw $e;
}
// 得到当前缓冲区的内容并清空,并关闭当前输出缓冲,ob_get_clean() 实质上是一起执行了ob_get_contents() 和 ob_end_clean()。
$content = ob_get_clean();
// 内容过滤标签
Hook::listen('view_filter', $content);
// 返回渲染后的模板
return $content;
}
接着上面的代码,对调用视图驱动做下简要分析,第一个调用config方法,配置模板引擎参数
thinkphp/library/think/view/driver/Think.php
/**
* 配置或者获取模板引擎参数
* @access private
* @param string|array $name 参数名
* @param mixed $value 参数值
* @return mixed
*/
public function config($name, $value = null)
{
if (is_array($name)) {
$this->template->config($name);
$this->config = array_merge($this->config, $name);
} elseif (is_null($value)) {
return $this->template->config($name);
} else {
// 设置模板引擎(thinkphp/library/think/Template.php)的参数tpl_replace_string为替换字符串,因为该变量不存在,所以会调用魔术方法__set,来设置引擎配置$this->config的tpl_replace_string
$this->template->$name = $value;
// 设置模板驱动$this->config的tpl_replace_string为替换字符串
$this->config[$name] = $value;
}
}
这里就是上面提到的魔术方法
thinkphp/library/think/Template.php
/**
* 模板引擎参数赋值
* @access public
* @param mixed $name
* @param mixed $value
*/
public function __set($name, $value)
{
$this->config[$name] = $value;
}
第二个调用fetch方法,渲染模板文件
thinkphp/library/think/view/driver/Think.php
/**
* 渲染模板文件
* @access public
* @param string $template 模板文件
* @param array $data 模板变量
* @param array $config 模板参数
* @return void
*/
public function fetch($template, $data = [], $config = [])
{
// 如果模板文件的扩展名为''
if ('' == pathinfo($template, PATHINFO_EXTENSION)) {
// 获取模板文件名,见自动定位模板文件
// $template = D:\phpstudy\PHPTutorial\WWW\fastadmin\public/../application/admin\view\auth\admin\index.html
$template = $this->parseTemplate($template);
}
// 模板不存在 抛出异常
if (!is_file($template)) {
throw new TemplateNotFoundException('template not exists:' . $template, $template);
}
// 记录视图信息
App::$debug && Log::record('[ VIEW ] ' . $template . ' [ ' . var_export(array_keys($data), true) . ' ]', 'info');
// 调用模板引擎(thinkphp/library/think/Template.php)渲染模板文件,见调用模板引擎篇
// 这里调用后,会输出渲染后的模板
$this->template->fetch($template, $data, $config);
}
/**
* 自动定位模板文件
* @access private
* @param string $template 模板文件规则
* @return string
*/
private function parseTemplate($template)
{
// 分析模板文件规则
$request = Request::instance();
// 获取视图根目录,如果模板文件名包含@,则会调用其他模块的模板文件,如$this->fetch('admin@member/edit');
if (strpos($template, '@')) {
// 跨模块调用
list($module, $template) = explode('@', $template);
}
// 如果设置了view_base,此目录作为所有视图文件的根目录,模块作为子目录
if ($this->config['view_base']) {
// 基础视图目录
$module = isset($module) ? $module : $request->module();
$path = $this->config['view_base'] . ($module ? $module . DS : '');
} else {// 如果没设置,视图文件存放在每个模块的view目录下面{view_path:模板起始路径,默认为''}
// $path = D:\phpstudy\PHPTutorial\WWW\fastadmin\public/../application/admin\view\
$path = isset($module) ? APP_PATH . $module . DS . 'view' . DS : $this->config['view_path'];
}
// view_depr:模板文件名分隔符,默认为 DIRECTORY_SEPARATOR
$depr = $this->config['view_depr'];
// 如果模板文件名不包含 /
if (0 !== strpos($template, '/')) {
// 将模板文件名中的 / 和 : 替换成目录分隔符
$template = str_replace(['/', ':'], $depr, $template);
// 字符串命名风格转换,将 Java 风格转换为 C 的风格
// $controller = auth.admin
$controller = Loader::parseName($request->controller());
if ($controller) {
// ①如果模板文件名为空,按照默认规则定位{auto_rule:1 解析为小写+下划线,2 全部转换小写}
if ('' == $template) {
// $template = auth\admin\index
$template = str_replace('.', DS, $controller) . $depr . (1 == $this->config['auto_rule'] ? Loader::parseName($request->action(true)) : $request->action());
} elseif (false === strpos($template, $depr)) {// ②如果模板文件名不为空,且不包含目录分隔符,如$this->fetch('edit');
// $template = auth\admin\edit
$template = str_replace('.', DS, $controller) . $depr . $template;
}
}
} else {// ③如果模板文件存在目录分隔符,且处于第一个字符,如$this->fetch('/menu');
// $template = menu
$template = str_replace(['/', ':'], $depr, substr($template, 1));
}
// view_suffix = html,下面为三种模板目录分隔类型
// ① D:\phpstudy\PHPTutorial\WWW\fastadmin\public/../application/admin\view\auth\admin\index.html
// ② D:\phpstudy\PHPTutorial\WWW\fastadmin\public/../application/admin\view\auth\admin\edit.html
// ③ D:\phpstudy\PHPTutorial\WWW\fastadmin\public/../application/admin\view\menu.html
return $path . ltrim($template, '/') . '.' . ltrim($this->config['view_suffix'], '.');
}