tp8异常必须继承think\exception子类,原生exception会被绕过框架拦截;404需通过route::miss()配置,render()无法捕获;推荐用app/exception.php闭包方式统一处理。

TP8 必须用 think\Exception 子类,原生 Exception 直接被绕过
TP8 的异常拦截机制做了底层重构:只有继承 \think\Exception 或其子类(如 \think\exception\HttpException、\think\exception\ValidateException)的异常才会进入框架的 render() 流程。写 throw new \Exception('xxx') 等于放弃所有自定义页面和状态码控制,PHP 会直接走原生错误处理,大概率白屏或显示堆栈。
常见错误现象:
- 控制器里
throw new Exception('测试')→ 访问时看到完整堆栈或空白页,而不是你的500.html - 日志里没记录,
app/exception.php完全不执行
正确做法:
- 统一改用
throw new \think\exception\HttpException(500, '服务异常') - 验证失败用
throw new \think\exception\ValidateException('用户名不能为空') - 想快速抛出 HTTP 异常,优先用
abort(404, '页面不存在')(它内部自动封装成HttpException)
404 不是异常,必须靠 Route::miss() 配置
TP8 明确将 404 归为「路由未匹配」,而非异常类型。所有对 http_exception_template、exception_tmpl、render() 的修改,对 404 完全无效。试图在 ExceptionHandler::render() 里判断 $e instanceof HttpException && $e->getStatusCode() === 404 是徒劳的。
唯一可靠方式是手动注册 Route::miss():
- 在
route/app.php文件末尾(所有Route::get()、Route::post()之后)添加:Route::miss(function () { return response()->view('error/404', [], 404); }); - 确保
config/app.php中'url_route_must' => true已启用,否则部分伪静态路径可能跳过miss回调 - 不要在
render()方法里对 404 做任何分支处理——它根本收不到
两种自定义入口:全局闭包 vs 自定义 Handler 类
TP8 支持两种轻量级接管方式,但二者互斥,不能共存:
- 推荐新手用
app/exception.php:直接返回一个闭包函数,无需注册、无类加载开销<?php use think\Response; use Throwable; return function (Throwable $e): Response { $code = $e instanceof \think\exception\HttpException ? $e->getStatusCode() : 500; return response(view("error/{$code}", ['exception' => $e]), $code); }; - 若需更复杂逻辑(如日志分级、异步上报),才建
app/exception/ExceptionHandler.php并在config/app.php中配置'exception_handle' => app\exception\ExceptionHandler::class;注意该类必须继承\think\exception\Handle,且render()返回值必须是\think\Response实例
关键区别:
- 闭包方式下,
http_exception_template配置完全失效,所有错误页由view()渲染 - Handler 类方式中,若你在
render()里没调用parent::render($request, $e),http_exception_template同样失效
error/ 模板目录位置与命名规则
模板文件必须放在 app/view/error/ 下,且文件名严格对应 HTTP 状态码,扩展名用 .html(TP8 默认不识别 .php 或 .tpl):
- 404 页面路径:
app/view/error/404.html - 500 页面路径:
app/view/error/500.html - 403 页面路径:
app/view/error/403.html
注意事项:
- 模板内可直接使用
$exception变量(来自闭包传入的view()参数),但无法访问$e['file']等旧版变量(那是think_exception.tpl的上下文) - 不要把模板放在
public/下——view()不读取 public 路径 - 调试时可临时在模板里加
<pre class="brush:php;toolbar:false;"><?php var_dump($exception); ?></pre>确认变量是否传入
最易忽略的一点:TP8 的 404 和 500 是两条完全独立的链路,前者只走 Route::miss(),后者才进异常处理器。混用或漏配其中任一,就会出现「有的错页生效、有的还是白屏」。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











