⚙️ 运行模式
ThinkAdmin 支持两种运行模式:开发模式(debug) 和 生产模式(product)。运行模式决定了系统的错误显示方式、缓存策略和性能表现。
📚 模式区别
🔨 开发模式
开发模式主要用于开发和调试阶段,系统会显示详细的错误信息,帮助开发者快速定位问题。
错误显示方式:开发模式下,当系统出现错误时,会显示完整的错误信息,包括:
- 错误类型和消息
- 错误发生的文件路径和行号
- 完整的调用堆栈
- SQL 查询语句(如果有)
模板缓存:开发模式下,模板每次请求都会重新编译,修改模板文件后立即生效,无需清理缓存。
SQL 日志:开发模式下,系统会自动记录所有 SQL 查询,方便调试和性能优化。
实际代码示例:
<?php
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\model\SystemUser;
class Test extends Controller
{
public function index()
{
// 开发模式下,SQL 查询会自动记录到日志
// 无需手动开启,系统会自动记录
$list = SystemUser::mk()->select();
// 开发模式下,可以使用 p() 函数输出调试信息
if (isDebug()) {
p($list); // 在页面上显示数据结构
}
$this->success('success', $list);
}
}适用场景:
- 功能开发和调试
- 问题排查和修复
- 性能分析和优化
- 代码测试和验证
🚀 生产模式
生产模式经过多项优化,提升系统性能、安全性和稳定性,是系统正式上线运行的推荐模式。
错误显示方式:生产模式下,当系统出现错误时,不会显示详细的错误信息,而是显示友好的提示页面,如"页面错误,请稍后再试"。这样可以避免敏感信息泄露,提升系统安全性。
模板缓存:生产模式下,编译后的模板会被缓存到 runtime/cache/template/ 目录,提升渲染速度。修改模板文件后需要清理缓存才能生效。
SQL 日志:生产模式下,系统不会记录 SQL 查询日志,减少 I/O 操作,提升性能。
实际代码示例:
<?php
namespace app\admin\controller;
use think\admin\Controller;
class Api extends Controller
{
public function data()
{
try {
// 业务逻辑
$data = $this->processData();
$this->success('success', $data);
} catch (\Exception $e) {
// 生产模式下,只返回友好提示,不暴露错误详情
if (isOnline()) {
$this->error('操作失败,请稍后再试');
} else {
// 开发模式下,显示详细错误信息
$this->error($e->getMessage());
}
}
}
}适用场景:
- 系统正式上线运行
- 高并发场景
- 对安全性要求高的场景
- 需要稳定运行的场景
🔧 判断模式
在代码中,可以使用 isDebug() 和 isOnline() 函数来判断当前运行模式。
判断开发模式:
// 使用 isDebug() 函数判断是否为开发模式
if (isDebug()) {
// 开发模式下的逻辑
echo "当前是开发模式";
// 可以显示详细的调试信息
$this->app->db->setLog(true); // 开启 SQL 日志
}判断生产模式:
// 使用 isOnline() 函数判断是否为生产模式
if (isOnline()) {
// 生产模式下的逻辑
echo "当前是生产模式";
// 隐藏错误详情,只显示友好提示
}使用服务类判断:
use think\admin\service\RuntimeService;
// 判断是否为开发模式
if (RuntimeService::isDebug()) {
// 开发模式逻辑
}
// 判断是否为生产模式
if (RuntimeService::isOnline()) {
// 生产模式逻辑
}🔧 应用场景
🐛 调试信息
在开发阶段,我们需要看到详细的调试信息,但在生产环境中,这些信息应该被隐藏。
代码实现:
<?php
namespace app\admin\controller;
use think\admin\Controller;
class Test extends Controller
{
public function index()
{
// 开发模式下,开启 SQL 日志记录
// 这样可以在日志文件中查看所有执行的 SQL 语句
if (isDebug()) {
$this->app->db->setLog(true);
}
// 查询数据(推荐使用模型方法)
$list = SystemUser::mk()->select();
// 开发模式下,使用 p() 函数输出调试信息
// p() 函数会在页面上以格式化的方式显示数据结构
if (isDebug()) {
p($list); // 输出调试信息,方便查看数据结构
}
$this->success('success', $list);
}
}说明:
$this->app->db->setLog(true)开启 SQL 日志,所有 SQL 查询会记录到日志文件p($list)函数用于输出调试信息,只在开发模式下使用- 生产模式下,这些调试代码不会影响性能,因为
isDebug()返回false
⚠️ 错误显示
在生产环境中,不应该向用户显示详细的错误信息,而应该显示友好的提示。
代码实现:
<?php
namespace app\admin\controller;
use think\admin\Controller;
class Api extends Controller
{
public function data()
{
try {
// 业务逻辑处理
$data = $this->processData();
$this->success('success', $data);
} catch (\Exception $e) {
// 根据运行模式返回不同的错误信息
if (isOnline()) {
// 生产模式:只返回友好提示,不暴露错误详情
// 这样可以避免泄露系统内部信息,提升安全性
$this->error('操作失败,请稍后再试');
} else {
// 开发模式:显示详细错误信息
// 包括错误消息、文件路径、行号等,方便调试
$this->error($e->getMessage());
}
}
}
private function processData()
{
// 模拟可能出错的业务逻辑
if (rand(0, 1)) {
throw new \Exception('数据库连接失败');
}
return ['status' => 'success'];
}
}说明:
- 使用
try-catch捕获异常 isOnline()判断是否为生产模式- 生产模式返回友好提示,开发模式返回详细错误
- 详细错误信息会记录到日志文件,方便后续排查
📝 日志级别
不同模式下,日志记录的详细程度应该不同。开发模式记录详细日志,生产模式只记录关键日志。
代码实现:
<?php
namespace app\admin\controller;
use think\admin\Controller;
class Log extends Controller
{
public function write()
{
$message = '用户操作日志';
$params = $this->request->param();
// 根据运行模式记录不同级别的日志
if (isDebug()) {
// 开发模式:记录详细日志
// debug 级别:记录调试信息
trace($message, 'debug');
// info 级别:记录请求参数
trace($params, 'info');
} else {
// 生产模式:只记录关键日志
// error 级别:只记录错误和重要操作
trace($message, 'error');
}
$this->success('日志记录成功');
}
}说明:
trace()函数用于记录日志,第一个参数是日志内容,第二个参数是日志级别- 日志级别:
debug<info<error - 开发模式记录所有级别,生产模式只记录
error级别 - 日志文件保存在
runtime/log/目录,按日期分割
⚙️ 配置说明
📁 文件位置
运行模式配置保存在 runtime/.env 文件中,系统启动时会自动读取该文件。
配置文件路径:runtime/.env
重要提示:
runtime/.env文件是后台自动生成的配置文件,请勿手动修改。所有配置应通过后台管理系统或代码中的RuntimeService::set()方法进行,系统会自动更新该文件。
配置文件格式(仅供参考,请勿手动编辑):
[RUNTIME]
mode = debug # debug=开发模式, product=生产模式
appmap[myadmin] = admin
domain[example.com] = admin⚙️ 配置说明
mode(运行模式)
debug:开发模式,显示详细错误信息,不缓存模板product:生产模式,显示友好提示,缓存模板
appmap(应用映射)
- 用于修改后台入口路径
- 格式:
appmap[新路径] = 原应用名 - 示例:
appmap[myadmin] = admin表示将/admin改为/myadmin
domain(域名绑定)
- 用于多域名访问不同应用
- 格式:
domain[域名] = 应用名 - 示例:
domain[example.com] = admin表示example.com访问admin应用
📖 读取配置
在代码中读取运行模式配置:
use think\admin\service\RuntimeService;
// 获取当前运行模式
$mode = RuntimeService::get('mode');
echo $mode; // 输出:debug 或 product
// 获取所有运行配置
$config = RuntimeService::get();
print_r($config);
// 输出:
// Array
// (
// [mode] => debug
// [appmap] => Array
// (
// [myadmin] => admin
// )
// [domain] => Array
// (
// [example.com] => admin
// )
// )🔄 切换模式
🖥️ 后台切换
在系统后台的"系统参数配置"页面可以切换运行模式,这是最安全和推荐的方式。
操作步骤:
- 登录后台管理系统
- 进入 系统管理 → 系统参数配置
- 找到 运行模式 配置项
- 选择 开发模式 或 生产模式
- 点击 保存 按钮
代码实现:
// app/admin/controller/Config.php
public function system()
{
$post = $this->request->post();
// 切换运行模式
// 从表单获取 runtime_mode 参数
if (isset($post['runtime_mode'])) {
// 判断是生产模式还是开发模式
$mode = $post['runtime_mode'] === 'product' ? 'product' : 'debug';
// 调用 RuntimeService::set() 方法设置运行模式
// 该方法会更新 runtime/.env 文件
RuntimeService::set($mode);
}
// 切换模式后,清理所有缓存
// 确保新模式的配置立即生效
RuntimeService::clear();
$this->success('切换成功');
}说明:
RuntimeService::set($mode)方法会自动更新runtime/.env文件中的mode配置runtime/.env文件是系统自动生成的,请勿手动修改- 切换后会自动清理缓存,确保新配置立即生效
- 需要超级管理员权限才能切换模式
💻 代码切换
如果需要在代码中切换模式(例如在命令行脚本中),可以使用以下方法:
use think\admin\service\RuntimeService;
// 切换到生产模式
// 参数 'product' 表示生产模式
RuntimeService::set('product');
// 切换到开发模式
// 参数 'debug' 表示开发模式
RuntimeService::set('debug');
// 切换后建议清理缓存
// 确保新模式的配置立即生效
RuntimeService::clear();实际应用示例:
<?php
// 在命令行脚本中切换模式
// 例如:php think deploy
use think\admin\service\RuntimeService;
// 部署到生产环境时,切换到生产模式
RuntimeService::set('product');
// 清理缓存
RuntimeService::clear();
echo "已切换到生产模式\n";注意事项:
- 切换模式需要使用超级管理员权限
- 切换后建议删除
runtime目录并刷新页面 - 请勿手动修改
runtime/.env文件:该文件是后台自动生成的配置文件,手动修改可能导致配置不同步或系统无法正确读取 - 所有配置应通过后台管理系统或代码中的
RuntimeService::set()方法进行
🗑️ 清理缓存
切换模式后,需要清理缓存才能生效。
💻 代码清理
在代码中清理缓存,这是最常用的方式:
use think\admin\service\RuntimeService;
// 清理所有缓存
// 包括:模板缓存、配置缓存、路由缓存等
RuntimeService::clear();说明:
RuntimeService::clear()会清理所有类型的缓存- 包括模板缓存、配置缓存、路由缓存等
- 清理后,系统会重新生成缓存
⌨️ 命令行清理
在命令行中清理缓存,适合在部署脚本中使用:
# 清理所有缓存目录
# --dir 参数表示清理目录缓存
php think clear --dir说明:
php think clear是 ThinkPHP 的命令行工具--dir参数表示清理目录缓存- 执行后会自动清理
runtime/cache/和runtime/temp/目录
🗂️ 手动删除
如果无法使用代码或命令行,可以手动删除缓存目录:
# 删除缓存目录
rm -rf runtime/cache/*
rm -rf runtime/temp/*
# Windows 系统使用
# rmdir /s /q runtime\cache
# rmdir /s /q runtime\temp说明:
runtime/cache/目录存放模板缓存、配置缓存等runtime/temp/目录存放临时文件- 删除后,系统会在下次请求时重新生成缓存
🎯 特定缓存
如果需要只清理特定类型的缓存,可以手动删除对应目录:
# 只清理模板缓存
rm -rf runtime/cache/template/*
# 只清理配置缓存
rm -rf runtime/cache/config/*
# 只清理路由缓存
rm -rf runtime/cache/route/*📊 模式差异
🔨 开发表现
错误显示:
- 显示完整错误信息,包括错误类型、消息、文件路径、行号、调用堆栈
- SQL 查询错误会显示完整的 SQL 语句
- 方便开发者快速定位问题
模板缓存:
- 每次请求都重新编译模板
- 修改模板文件后立即生效,无需清理缓存
- 适合频繁修改模板的开发阶段
SQL 日志:
- 自动记录所有 SQL 查询到日志文件
- 可以在
runtime/log/目录查看 SQL 日志 - 方便调试和性能优化
实际代码示例:
<?php
// 开发模式下的代码示例
use think\admin\Controller;
use think\admin\model\SystemUser;
class User extends Controller
{
public function index()
{
// 开发模式下,SQL 查询会自动记录
// 无需手动开启,系统会自动记录到日志
$list = SystemUser::mk()->select();
// 开发模式下,可以使用 p() 函数输出调试信息
if (isDebug()) {
p($list); // 在页面上显示数据结构
}
$this->success('success', $list);
}
}🚀 生产表现
错误显示:
- 只显示友好提示:"页面错误,请稍后再试"
- 不显示错误详情,避免泄露系统信息
- 详细错误信息会记录到日志文件
模板缓存:
- 编译后的模板缓存到
runtime/cache/template/目录 - 提升模板渲染速度,减少重复编译
- 修改模板后需要清理缓存才能生效
SQL 日志:
- 不记录 SQL 查询日志,减少 I/O 操作
- 提升系统性能,适合高并发场景
- 只记录错误和异常信息
实际代码示例:
<?php
// 生产模式下的代码示例
class Api extends Controller
{
public function data()
{
try {
// 业务逻辑处理
$data = $this->processData();
$this->success('success', $data);
} catch (\Exception $e) {
// 生产模式下,只返回友好提示
// 详细错误信息会记录到日志文件
if (isOnline()) {
// 记录错误到日志
trace_file($e);
// 返回友好提示
$this->error('操作失败,请稍后再试');
} else {
// 开发模式显示详细错误
$this->error($e->getMessage());
}
}
}
}🔧 修改后台入口
默认后台入口为 /admin,容易被猜测,建议修改。
❓ 修改原因
默认的 /admin 路径容易被攻击者猜测和扫描,修改为自定义路径可以:
- 降低被扫描发现的概率
- 提升系统安全性
- 防止未授权访问
💻 代码实现
代码在 app/admin/controller/Config.php 中:
// app/admin/controller/Config.php
public function system()
{
$post = $this->request->post();
// 修改后台入口路径
// 从表单获取 xpath 参数,这是新的入口路径
if (!empty($post['xpath'])) {
// 验证格式:只能包含字母、数字、下划线
// 正则表达式:^[a-zA-Z_][a-zA-Z0-9_]*$
// 必须以字母或下划线开头,后面可以跟字母、数字、下划线
if (!preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $post['xpath'])) {
$this->error('后台入口格式错误!');
}
// 检查是否与现有应用冲突
// 如果新路径不是 'admin',需要检查是否已存在同名应用或插件
if ($post['xpath'] !== 'admin') {
// 检查 app 目录下是否已存在同名应用
if (is_dir(syspath("app/{$post['xpath']}")) || !empty(Plugin::get($post['xpath']))) {
$this->error('已存在该应用!');
}
}
// 设置应用映射:新路径 => 原admin应用
// RuntimeService::set() 的第二个参数是应用映射数组
// 格式:['新路径' => '原应用名']
RuntimeService::set(null, [$post['xpath'] => 'admin']);
}
// 保存其他配置到系统配置表
foreach ($post as $k => $v) {
sysconf($k, $v);
}
$this->success('保存成功');
}代码说明:
preg_match()验证路径格式,确保只包含字母、数字、下划线is_dir()检查是否已存在同名应用目录Plugin::get()检查是否已存在同名插件RuntimeService::set()设置应用映射,将新路径映射到原admin应用sysconf()保存其他配置到系统配置表
📝 使用示例
代码修改
在代码中修改后台入口:
use think\admin\service\RuntimeService;
// 将后台入口从 /admin 改为 /myadmin
// RuntimeService::set() 的第一个参数是运行模式(null 表示不修改)
// 第二个参数是应用映射数组
RuntimeService::set(null, ['myadmin' => 'admin']);
// 修改后,访问地址变为:
// http://yourdomain.com/myadmin
// http://yourdomain.com/myadmin.html
// 原来的 /admin 路径将无法访问应用示例:
<?php
// 在部署脚本中修改后台入口
// 例如:php think deploy
use think\admin\service\RuntimeService;
// 生成随机入口路径,提升安全性
$randomPath = 'admin_' . substr(md5(time()), 0, 8);
RuntimeService::set(null, [$randomPath => 'admin']);
echo "后台入口已修改为:/{$randomPath}\n";后台修改
在系统后台修改:
- 登录后台管理系统
- 进入 系统管理 → 系统参数配置
- 找到 后台入口路径 配置项
- 输入新的入口路径(只能包含字母、数字和下划线)
- 点击 保存 按钮
注意事项:
- 入口路径只能包含字母、数字和下划线,不能包含其他字符
- 不能与现有应用目录冲突,例如不能使用
index、api等已存在的应用名 - 修改后原有
/admin入口将被禁用,只能通过新路径访问 - 建议使用不易猜测的路径,如
myadmin2024、sys_manage、admin_abc123等 - 修改后需要记住新路径,否则无法访问后台
📋 常见问题
❓ 页面无法访问
问题描述:切换运行模式后,页面无法正常访问,可能出现空白页面或错误提示。
原因分析:切换模式后,旧的缓存可能仍然存在,导致系统使用旧的配置,从而出现访问异常。
解决方法:
# 删除缓存目录
# 清理模板缓存、配置缓存等
rm -rf runtime/cache/*
rm -rf runtime/temp/*
# 检查文件权限
# 确保 runtime 目录有写入权限
chmod -R 755 runtime如果仍然无法访问,按以下步骤排查:
检查 PHP 错误日志:查看是否有 PHP 错误
# 查看 PHP 错误日志 tail -f /var/log/php_errors.log # 或查看 ThinkAdmin 日志 tail -f runtime/log/$(date +%Y%m%d).log检查文件权限:确保
runtime目录有写入权限# 检查目录权限 ls -la runtime/ # 如果权限不足,修改权限 chmod -R 755 runtime chown -R www-data:www-data runtime # Linux检查数据库连接:检查数据库配置是否正确
// 在代码中测试数据库连接 try { $this->app->db->connect(); echo "数据库连接成功"; } catch (\Exception $e) { echo "数据库连接失败:" . $e->getMessage(); }
❓ 模板不生效
问题描述:在生产模式下修改了模板文件,但页面显示的还是旧内容。
原因分析:生产模式下,模板会被编译并缓存到 runtime/cache/template/ 目录。修改模板文件后,需要清理缓存才能看到新内容。
解决方法:
// 方式1:代码清理(推荐)
use think\admin\service\RuntimeService;
// 清理所有缓存,包括模板缓存
RuntimeService::clear();// 方式2:命令行清理
// 使用 ThinkPHP 的命令行工具清理缓存
php think clear --dir// 方式3:手动删除模板缓存
// 只删除模板缓存,不影响其他缓存
rm -rf runtime/cache/template/*说明:
RuntimeService::clear()会清理所有类型的缓存php think clear --dir会清理目录缓存- 手动删除只清理模板缓存,其他缓存不受影响
❓ 判断运行模式
问题描述:在代码中需要根据运行模式执行不同的逻辑,如何判断当前是开发模式还是生产模式?
解决方法:
// 方式1:使用 isDebug() 函数(推荐)
// isDebug() 返回 true 表示开发模式,false 表示生产模式
if (isDebug()) {
// 开发模式下的逻辑
echo "当前是开发模式";
// 可以显示详细的调试信息
} else {
// 生产模式下的逻辑
echo "当前是生产模式";
// 隐藏错误详情,只显示友好提示
}// 方式2:使用 isOnline() 函数
// isOnline() 返回 true 表示生产模式,false 表示开发模式
if (isOnline()) {
// 生产模式下的逻辑
echo "当前是生产模式";
} else {
// 开发模式下的逻辑
echo "当前是开发模式";
}// 方式3:使用 RuntimeService 服务类
use think\admin\service\RuntimeService;
// 判断是否为开发模式
if (RuntimeService::isDebug()) {
// 开发模式逻辑
}
// 判断是否为生产模式
if (RuntimeService::isOnline()) {
// 生产模式逻辑
}
// 获取运行模式字符串
$mode = RuntimeService::get('mode');
if ($mode === 'debug') {
echo "开发模式";
} elseif ($mode === 'product') {
echo "生产模式";
}❓ 生产模式调试
问题描述:生产模式下错误信息被隐藏,如何查看详细的错误信息进行调试?
解决方法:
方式1:查看日志文件
生产模式下,所有错误和异常都会记录到日志文件,可以通过查看日志来调试:
// 在代码中读取日志文件
$logFile = syspath('runtime/log/' . date('Ymd') . '.log');
if (file_exists($logFile)) {
// 读取日志内容
$logs = file_get_contents($logFile);
// 处理日志内容,例如显示最后 100 行
$lines = explode("\n", $logs);
$lastLines = array_slice($lines, -100);
echo implode("\n", $lastLines);
}方式2:记录异常到文件
在代码中捕获异常并记录到日志文件:
try {
// 业务代码
$data = $this->processData();
$this->success('success', $data);
} catch (\Exception $e) {
// 记录异常到日志文件
// trace_file() 会将异常信息记录到 runtime/log/ 目录
trace_file($e);
// 返回友好提示给用户
$this->error('操作失败,请稍后再试');
}方式3:临时切换到开发模式
如果问题比较复杂,可以临时切换到开发模式进行调试:
// 临时切换到开发模式
use think\admin\service\RuntimeService;
RuntimeService::set('debug');
// 调试完成后,切回生产模式
RuntimeService::set('product');
RuntimeService::clear();方式4:在后台查看日志
系统后台提供了日志查看功能,可以查看系统操作日志和错误日志:
- 登录后台管理系统
- 进入 系统管理 → 系统日志
- 查看错误日志和操作日志
❓ 开发模式生产
问题描述:开发模式可以用于生产环境吗?会有什么影响?
答案:不建议在生产环境使用开发模式。
原因分析:
安全风险:开发模式会显示详细错误信息,包括文件路径、数据库配置等敏感信息,存在安全风险。
性能影响:开发模式不缓存模板,每次请求都重新编译,影响性能。
日志占用:开发模式会记录详细的 SQL 日志,占用大量磁盘空间。
实际对比:
// 开发模式下的错误显示
// 会显示完整的错误信息、文件路径、行号等
// 例如:
// Fatal error: Call to undefined method in /path/to/file.php on line 123
// Stack trace: ...
// 生产模式下的错误显示
// 只显示友好提示
// 例如:页面错误,请稍后再试建议:
- 开发阶段使用开发模式
- 测试阶段可以临时使用开发模式
- 生产环境必须使用生产模式
❓ 查看配置
问题描述:如何在代码中查看当前的运行模式配置?
解决方法:
use think\admin\service\RuntimeService;
// 获取当前运行模式
// 返回 'debug' 或 'product'
$mode = RuntimeService::get('mode');
echo $mode; // 输出:debug 或 product
// 获取所有运行配置
// 返回包含 mode、appmap、domain 的数组
$config = RuntimeService::get();
print_r($config);
// 输出示例:
// Array
// (
// [mode] => debug
// [appmap] => Array
// (
// [myadmin] => admin
// )
// [domain] => Array
// (
// [example.com] => admin
// )
// )
// 获取特定配置项
$appmap = RuntimeService::get('appmap', []);
print_r($appmap);
// 输出:Array ( [myadmin] => admin )查看配置文件(仅用于查看,请勿手动修改):
# 直接查看配置文件(仅用于查看,请勿手动修改)
cat runtime/.env
# 输出示例:
# [RUNTIME]
# mode = debug
# appmap[myadmin] = admin
# domain[example.com] = admin📸 演示截图


