thinkphp 6 中 try-catch 必须捕获 \think\exception 或其子类(如 \think\db\exception\pdoexception),不能仅用 exception,否则框架异常会漏捕;推荐写法为 catch (\think\exception $e) 并配合 log::error('msg', $e) 记录完整上下文。

ThinkPHP 6 中 try catch 捕获异常的正确写法
直接用 try + catch 是可行的,但必须捕获 ThinkPHP 自身抛出的异常类,不能只写 Exception —— 否则大部分框架层错误(比如数据库连接失败、模型验证失败)会漏掉。
ThinkPHP 6 的核心异常都继承自 think\Exception,而更常用的是具体子类,如 think\db\exception\DataNotFoundException、think\model\exception\ModelNotFoundException 等。实际开发中建议按需捕获,或统一用 think\Exception 做兜底。
- 不要只写
catch (Exception $e),它无法捕获think\Exception及其子类(因为它们不继承 PHP 原生Exception) - 推荐写法:
catch (\think\Exception $e)或更精确的catch (\think\db\exception\PDOException $e) - 如果用了命名空间,记得加反斜杠
\,否则可能因自动导入失败而捕获不到
捕获数据库操作异常时的典型场景
执行 Db::table('user')->insert(...) 或 UserModel::create(...) 失败时,不会返回 false,而是直接抛异常。这时候没做 catch 就会触发全局异常处理,页面显示调试信息或 500 错误。
常见错误现象:本地开发能看到详细报错,但上线后变成空白页或“系统繁忙”,就是因为没主动捕获并处理。
- 插入重复主键或唯一索引冲突 → 抛出
\think\db\exception\PDOException - 查询不存在记录且使用了
findOrFail()→ 抛出\think\model\exception\ModelNotFoundException - SQL 语法错误或字段不存在 → 抛出
\think\db\exception\DataNotFoundException - 建议在关键写操作周围包一层
try/catch,并记录日志或返回用户友好提示,而不是让异常冒泡
Log::error() 记录异常信息的注意事项
捕获到异常后,用 Log::error() 记录是常规操作,但要注意传参方式 —— 直接传 $e->getMessage() 会丢失堆栈和上下文,不利于排查。
ThinkPHP 的 Log::error() 支持传入整个 Exception 对象,它会自动提取完整 trace。
- ✅ 推荐:
Log::error('用户注册失败', $e) - ❌ 避免:
Log::error('用户注册失败: ' . $e->getMessage()) - 如果要额外带业务参数,可用关联数组:
Log::error('用户注册失败', ['uid' => $uid, 'exception' => $e]) - 注意日志驱动配置(如
type设为file或trace),否则可能写不进日志文件
全局异常处理 vs 局部 try catch 的取舍
ThinkPHP 已内置全局异常处理器(app/exception/Handle.php),它负责拦截未被捕获的异常并渲染页面。但这不意味着你可以省略局部 try/catch。
全局处理适合兜底和统一响应格式,而局部捕获用于「可预期的失败场景」—— 比如第三方 API 调用超时、库存扣减失败需要回滚事务、用户提交非法数据需提示具体字段错误。
- 事务内操作必须用局部
try/catch,否则Db::transaction()不会自动 rollback - 调用
Http::post()等外部接口时,网络异常、超时、HTTP 状态码非 2xx 都应单独捕获处理 - 全局异常处理器里的
render()方法不适合做业务逻辑判断,只适合统一输出 JSON 或视图 - 容易被忽略的一点:
catch块里如果再次抛出异常(比如throw new ValidateException(...)),要确认新异常是否仍能被全局处理器捕获
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











