thinkphp日志与异常处理需满足三前提:php底层错误日志必须开启;tp日志通道需启用且level含error;app_debug必须为false。pdoexception和fatal error因发生时机早于框架初始化,无法进入runtime/log,须在public/index.php顶部用register_shutdown_function兜底并重写mysql::connect()捕获。

ThinkPHP 的日志和异常处理不是“配了就能用”的功能,而是有明确的触发边界和执行时机。很多问题表面是日志不写、异常白屏,实际是流程没走到那一步——比如 PDO 连接失败发生在日志驱动初始化之前,Fatal error 根本不进框架,APP_DEBUG=true 时所有 Log::error() 都被跳过。
日志写不进去,先看这三件事
- PHP 底层错误日志必须打开:确认
php.ini中log_errors = On,error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED,且error_log指向可写路径(如/var/log/php_errors.log),改完重启 PHP-FPM - ThinkPHP 日志通道得“活”着:检查
config/log.php中'default' => 'file'是否正确;'level'数组是否包含'error';'close' => false(设为 true 就彻底关了) - APP_DEBUG 必须为 false:开发时设为 true,错误直接打屏,Log::error() 和未捕获异常都不会落地;只有
APP_DEBUG=false时,异常才走app/exception/Handler.php的report()方法并尝试写日志
哪些异常根本进不了 runtime/log?
-
PDOException(如数据库连接失败):常发生在Db::connect()阶段,此时 Log 驱动还没初始化(因为要读数据库配置,而配置又依赖数据库连接,死循环) -
Parse error、Class not found、Fatal error:PHP 解析或加载阶段就崩溃,连public/index.php都没跑完,框架完全没机会介入 - Composer autoloader 失败、
app/common.php加载前的错误:代码根本没执行到Log::error()那一行
让关键错误至少留下痕迹的硬招
- 在
public/index.php最顶部加兜底:register_shutdown_function(function () { if ($e = error_get_last()) { $msg = sprintf("[%s] %s in %s on line %d", date('Y-m-d H:i:s'), $e['message'], $e['file'], $e['line']); file_put_contents('/tmp/think-fatal.log', $msg . "\n", FILE_APPEND | LOCK_EX); } }); - 重写
think\db\connector\Mysql::connect(),在new PDO()外加catch (\PDOException $e),手动调Log::record('DB connect fail: ' . $e->__toString(), 'error') - 记录异常别只写
$e->getMessage():用Log::info($e->__toString())才能输出完整堆栈、文件、行号和上下文变量
异常页面为什么还是白屏或不生效?
- TP8 只接管
think\Exception及其子类:写throw new \Exception()等于放弃框架保护,必须改用throw new \think\exception\HttpException(500, 'xxx')或abort(500) - 404 不是异常,不能靠
Handler::render()拦截:唯一可靠方式是在route/app.php所有路由定义之后加Route::miss(fn() => response()->view('error/404', [], 404)) -
render()返回值必须是think\Response实例:返回数组、字符串或裸json()会导致框架二次包装,混入默认页脚;API 场景用return json([...], 500),HTML 场景用return response(view(...), 500)
日志写了但看不到?查这几个点
-
config/log.php中'realtime_write' => true是否开启,否则可能缓存数秒才落盘 -
runtime/log/目录权限是否属于 Web 进程用户(如www-data),权限不足会静默失败 - 别信动态路径如
date('Y-m') . '/' . date('d') . '.log':ThinkPHP 不自动创建多级目录,runtime/log/2026-09/02.log若目录不存在,日志直接丢弃
不复杂,但容易忽略。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











