引言:为什么基础错误处理只是开始
每位PHP开发者都熟悉try/catch结构。但当项目增长到数千行代码,服务器负载变高时,简单的异常捕获就不够了。高级错误处理不仅仅是“捕获并忘记”,而是一个完整的系统:从日志记录到将警告转换为异常。
在本文中,我们将探讨帮助您编写可靠且容错代码的技术:多重catch、自定义异常类、全局处理程序以及与PSR-3日志记录器的集成。本文面向已熟悉PHP基础的开发者。
1. 多重catch块与异常层次结构
从PHP 7.1开始,您可以在一个try块中捕获不同类型的异常。这允许您有针对性地响应错误:
<?phpclass DatabaseException extends \\Exception {}class ValidationException extends \\Exception {}
try { // 可能抛出不同异常的代码 $user = $db->query('SELECT ...'); if (!$user) { throw new DatabaseException('查询错误'); } if (empty($user['email'])) { throw new ValidationException('Email为必填项'); }} catch (DatabaseException $e) { // 记录数据库错误 error_log('数据库错误: ' . $e->getMessage()); echo '服务器临时错误,请稍后重试。';} catch (ValidationException $e) { // 向用户显示清晰的消息 echo '错误: ' . htmlspecialchars($e->getMessage());} catch (\\Throwable $e) { // 捕获所有其他错误(包括Error) error_log('严重错误: ' . $e->getMessage()); echo '严重错误。';}?>为什么这很重要?每种异常类型都需要不同的响应。数据库错误——对用户隐藏细节,验证错误——显示带有字段高亮的表单,严重错误——发送通知给管理员。
请注意\\Throwable——这是一个接口,Exception和Error(PHP致命错误)都实现了它。在最后一个catch块中使用它,以确保不会遗漏任何错误。
2. 自定义异常类:扩展标准
标准\\Exception类提供了基本功能。但在实际项目中,创建自己的异常层次结构很方便——这简化了调试和处理。
Web应用程序的结构示例:
<?phpnamespace App\\Exceptions;
// 应用程序基础异常class AppException extends \\RuntimeException{ protected $context = [];
public function __construct(string $message = '', int $code = 0, ?\\Throwable $previous = null, array $context = []) { parent::__construct($message, $code, $previous); $this->context = $context; }
public function getContext(): array { return $this->context; }}
// HTTP错误异常class HttpException extends AppException{ private int $statusCode;
public function __construct(int $statusCode, string $message = '', array $context = []) { $this->statusCode = $statusCode; parent::__construct($message, $statusCode, null, $context); }
public function getStatusCode(): int { return $this->statusCode; }}
// 使用throw new HttpException(404, '页面未找到', ['uri' => $_SERVER['REQUEST_URI']]);?>优点:
- 可以传递额外的上下文(请求参数、用户ID)——这简化了日志记录。
- 异常按含义分组:
HttpException、ValidationException、PaymentException。