PHP中try...catch仅捕获显式throw的Exception或Error,对网络超时、HTTP 500、JSON解析失败等非异常情况无感;须手动检查返回值或统一转异常才能真正触发catch。

PHP 中用 try...catch 包裹服务调用,不是“加个壳”就完事——它只捕获抛出的 Exception 或 Error(PHP 7+),对网络超时、HTTP 500、JSON 解析失败、空响应等**非异常情况完全无感**。不手动检查返回值或封装错误逻辑,try...catch 就是摆设。
哪些服务调用会真正触发 catch?
只有显式 throw 的地方才会进 catch 块。比如:
-
file_get_contents("https://api.example.com")即使返回 false 或空字符串,也不会抛异常(除非启用了stream_context_set_option($ctx, 'http', 'ignore_errors', false)并配合自定义错误处理器) - Guzzle HTTP 客户端默认在 4xx/5xx 响应时 不抛异常,需显式调用
$response->raiseForStatus() - PDO 默认是
PDO::ERRMODE_SILENT,执行失败只设$pdo->errorInfo(),不会 throw;必须先设$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION) - 你自己写的
UserService::getById()如果内部没写throw new RuntimeException(...),外面套try...catch也毫无意义
怎么让服务调用「可被捕获」?
关键在「统一错误出口」:把各种失败路径都转成异常。常见做法:
- 使用 Guzzle 时,在请求后立即调用
$response->raiseForStatus(),它会在状态码非 2xx 时抛GuzzleHttp\Exception\BadResponseException - 封装 cURL 时,检查
curl_errno($ch)和curl_getinfo($ch, CURLINFO_HTTP_CODE),手动throw new HttpException(...) - 调用第三方 SDK(如阿里云 OSS、微信支付)前,确认其是否开启异常模式;例如
new \WeChat\Pay($config)默认失败返回数组,得自己判断isset($result['return_code']) && $result['return_code'] !== 'SUCCESS' - 对 JSON 解析结果强制校验:
$data = json_decode($raw, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new JsonException(json_last_error_msg()); }
trycatch 里该写什么?别只写 echo 或 log
生产环境的 catch 不是终点,而是错误分发点:
立即学习“PHP免费学习笔记(深入)”;
- 区分异常类型处理:
catch (GuzzleHttp\Exception\ConnectException $e)是网络不通,catch (DomainException $e)可能是参数非法,不能一概die() - 避免裸露敏感信息:不要直接
echo $e->getMessage(),尤其在 API 返回中;应返回通用错误码 + 日志记录完整 trace - 注意异常链:若在 catch 中重抛新异常,用
throw new ServiceException("上游用户服务不可用", 0, $e)保留原始上下文 - 资源清理要靠
finally或显式关闭:比如try { $fp = fopen(...); ... } finally { if (isset($fp)) fclose($fp); }
真正安全的服务调用,靠的不是 try...catch 的语法存在,而是每一层返回值都被检查、每一种失败都被归类、每一个异常都有明确语义和处置路径。漏掉 HTTP 状态码判断,比忘了写 try 更危险。










