本文目录导读:

在 PHP 项目中,异常(Exception) 和 finally 是错误处理的关键机制,以下是它们的核心概念、用法及最佳实践。
异常(Exception)
基本结构
try {
// 可能抛出异常的代码
if ($somethingWrong) {
throw new Exception("Something went wrong");
}
} catch (Exception $e) {
// 处理异常
echo "Caught: " . $e->getMessage();
}
异常类层级
- PHP 内置异常:
Exception、RuntimeException、InvalidArgumentException等 - 自定义异常类(推荐继承
Exception)
class ValidationException extends Exception {}
class DatabaseException extends Exception {}
多 catch 捕获
try {
// ...
} catch (ValidationException $e) {
// 处理验证错误
} catch (DatabaseException $e) {
// 处理数据库错误
} catch (Exception $e) {
// 兜底处理
}
finally 块
作用
无论是否抛出异常,finally 块中的代码必定执行,常用于:
- 关闭数据库连接
- 释放文件句柄
- 恢复全局状态
- 记录日志
语法
try {
// 可能异常的代码
} catch (Exception $e) {
// 异常处理
} finally {
// 总是执行,用于清理资源
$db->close();
}
示例:文件操作
function readFile(string $path): string {
$handle = fopen($path, 'r');
if (!$handle) {
throw new RuntimeException("Cannot open file");
}
try {
$content = fread($handle, filesize($path));
return $content;
} finally {
fclose($handle); // 确保文件关闭
}
}
finally 与 return 的交互
关键规则
- finally 中的 return 会覆盖 try/catch 中的 return
- finally 中无 return,则返回 try/catch 中的值
function test(): string {
try {
return "from try";
} finally {
return "from finally"; // 最终返回这个
}
}
echo test(); // 输出: from finally
最佳实践
- 不要在 finally 中使用 return(除非有明确意图)
- 避免在 finally 中抛出异常(会覆盖原始异常)
异常与 finally 的典型场景
数据库事务
$db->beginTransaction();
try {
$db->query("UPDATE users SET ...");
$db->query("INSERT INTO logs ...");
$db->commit();
} catch (Exception $e) {
$db->rollBack();
throw $e; // 重新抛出
} finally {
$db->close(); // 确保连接释放
}
API 响应封装
function apiCall(string $url): array {
$ch = curl_init($url);
try {
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
if (curl_errno($ch)) {
throw new CurlException(curl_error($ch));
}
return json_decode($response, true);
} finally {
curl_close($ch); // 总是关闭 curl 句柄
}
}
PHP 8+ 新特性
匹配表达式(Match Expression)
- 不直接处理异常,但可用于条件判断后抛异常
构造器属性提升 + 异常
class UserController {
public function __construct(
private UserRepository $repo
) {}
public function show(int $id): User {
$user = $this->repo->find($id);
if (!$user) {
throw new NotFoundException("User not found");
}
return $user;
}
}
常见陷阱与最佳实践
| 陷阱 | 说明 | 解决方案 |
|---|---|---|
| 吞掉异常(catch 空) | catch (Exception $e) {} 隐藏错误 |
至少记录日志或重新抛出 |
| finally 中抛出异常 | 会覆盖原始异常 | 用 try-catch 包裹 finally 代码 |
| 过度使用异常做流程控制 | 性能差且难以维护 | 只用于真正的错误情况 |
| 未捕获的异常导致 500 | 生产环境应设置全局异常处理器 | 使用 set_exception_handler() |
全局异常处理器示例
set_exception_handler(function (Throwable $e) {
// 生产环境记录日志,返回友好错误页面
error_log($e->getMessage());
http_response_code(500);
echo json_encode(['error' => 'Internal Server Error']);
});
- 异常:用于处理运行时错误,通过 try-catch 捕获
- finally:无论是否异常,保证资源清理代码执行
- 组合使用:数据库事务、文件操作、API 请求等需要资源管理的场景
- 避免陷阱:不在 finally 中 return/throw,不吞掉异常
合理使用异常和 finally,能让 PHP 项目更加健壮、可维护。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播