PHP 错误处理:try/catch 与高级技术

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

PHP 错误处理:从 try/catch 到工业级解决方案

\n\n

每位 PHP 开发者都会遇到错误。基础的 try/catch 只是冰山一角。本文将深入探讨高级错误处理技术,将脆弱的代码转变为能够正确应对任何故障的可靠系统。

\n\n

1. 深入理解 try/catch:finally 块与多重 catch

\n\n

标准的 try/catch 是基础,但许多人忘记了 finally 块,它无论是否发生异常都会执行。这是关闭资源(文件、数据库连接)的理想位置。

\n\n
<?php\nfunction processFile(string $filename): void {\n    $handle = fopen($filename, 'r');\n    if (!$handle) {\n        throw new \\RuntimeException("无法打开文件: $filename");\n    }\n    \n    try {\n        // 处理文件\n        while (($line = fgets($handle)) !== false) {\n            // ... 处理逻辑\n        }\n    } catch (\\RuntimeException $e) {\n        // 特定于输入/输出错误的处理\n        error_log("读取文件错误: " . $e->getMessage());\n        throw $e; // 向上抛出\n    } catch (\\Exception $e) {\n        // 处理任何其他异常\n        error_log("未知错误: " . $e->getMessage());\n        throw $e;\n    } finally {\n        fclose($handle); // 始终关闭文件\n    }\n}\n?>
\n\n

重要提示: catch 块的顺序很重要。更具体的异常(例如 \\RuntimeException)应放在通用异常(\\Exception)之前。否则,特定的块将永远不会被执行。

\n\n

2. 自定义异常类:语义与层次结构

\n\n

内置异常(PDOException、RuntimeException)通常信息不足。创建您自己的异常层次结构,以便按类型区分错误并简化其处理。

\n\n
<?php\n// 应用程序基础异常\nclass AppException extends \\Exception {}\n\n// 验证错误\nclass ValidationException extends AppException {\n    private array $errors;\n    \n    public function __construct(array $errors, string $message = "验证错误") {\n        parent::__construct($message, 422);\n        $this->errors = $errors;\n    }\n    \n    public function getErrors(): array {\n        return $this->errors;\n    }\n}\n\n// 访问错误\nclass AccessDeniedException extends AppException {\n    public function __construct(string $message = "访问被拒绝") {\n        parent::__construct($message, 403);\n    }\n}\n\n// 使用示例\nfunction registerUser(array $data): void {\n    $errors = [];\n    \n    if (empty($data['email'])) {\n        $errors['email'] = '电子邮件为必填项';\n    }\n    if (empty($data['password'])) {\n        $errors['password'] = '密码为必填项';\n    }\n    \n    if (!empty($errors)) {\n        throw new ValidationException($errors);\n    }\n    \n    // 注册逻辑...\n}\n\ntry {\n    registerUser(['email' => '']);\n} catch (ValidationException $e) {\n    // 特定处理:返回包含错误的 JSON\n    http_response_code(422);\n    echo json_encode(['errors' => $e->getErrors()]);\n} catch (AccessDeniedException $e) {\n    http_response_code(403);\n    echo json_encode(['error' => $e->getMessage()]);\n} catch (AppException $e) {\n    // 对所有其他应用程序错误的通用处理\n    http_response_code(500);\n    echo json_encode(['error' => '服务器内部错误']);\n}\n?>
\n\n

建议: 使用 HTTP 状态码(400、403、422、500)作为异常代码——这简化了与 REST API 的集成。

\n\n

3. 全局错误处理器:ErrorHandler 和 ShutdownHandler

\n\n

并非所有错误都能通过 try/catch 捕获。致命错误(E_ERROR)、警告(E_WARNING)和解析错误

博客

书籍推荐