PHP 错误处理:从基本结构到专业模式
任何 PHP 开发者迟早都会遇到代码行为与预期不符的情况。文件未找到、数据库不可用、用户输入了无效数据——这些都是异常情况。妥善的错误处理能将脆弱的应用程序转变为可靠的系统。在本文中,我们将深入探讨 PHP 中错误处理的各个方面:从简单的 try/catch 到创建自定义异常类和全局处理器。
1. 基础:try/catch 和 throw 结构
在 PHP 中,异常是 Exception 类(或其子类)的对象。基本机制由三个关键字组成:
try— 执行潜在危险代码的块;catch— 捕获异常的块;throw— “抛出”异常的运算符。
来看一个最简单的例子:
<?phpfunction divide($a, $b) { if ($b == 0) { throw new Exception('除以零不可能'); } return $a / $b;}
try { echo divide(10, 0);} catch (Exception $e) { echo '错误:' . $e->getMessage();}?>当执行到 throw 时,PHP 会立即离开当前函数并寻找匹配的 catch 块。如果找到 catch,则从其处继续执行。如果未找到,则会发生致命错误。
重要提示:从 PHP 7 开始,大多数内部错误(例如除以零)会抛出 DivisionByZeroError 类的异常。要捕获它们,需要指定相应的类型。
2. 高级功能:多重 catch 和 finally
通常,在一个 try 块中可能发生不同类型的异常。PHP 允许为不同的类创建多个 catch 块:
<?phpclass ValidationException extends Exception {}class DatabaseException extends Exception {}
try { // 可能抛出不同异常的代码} catch (ValidationException $e) { echo '验证错误:' . $e->getMessage();} catch (DatabaseException $e) { echo '数据库错误:' . $e->getMessage();} catch (Exception $e) { // 所有其他异常的通用处理器 echo '未知错误:' . $e->getMessage();}?>catch 块的顺序很重要:PHP 会按顺序检查它们,第一个类型匹配的块会捕获异常。因此,通用的 catch (Exception $e) 总是放在最后。
finally 块在任何情况下都会执行——无论是在 try 成功完成后,还是在捕获异常后,甚至如果在 catch 中有 return 语句。这是关闭文件、释放资源或写入日志的理想位置:
<?phpfunction readConfig($filename) { $handle = fopen($filename, 'r'); if (!$handle) { throw new Exception('无法打开文件'); } try { // 读取数据 return fread($handle, filesize($filename)); } finally { fclose($handle); // 即使发生异常,文件也会关闭 }}?>3. 自定义异常类和全局处理器
创建自己的异常类是结构化代码的强大工具。只需继承 Exception:
<?phpclass InvalidEmailException extends Exception { public function __construct($email, $code = 0, Throwable $previous = null) { $message = "邮箱 '$email' 格式无效"; parent::__construct($message, $code, $previous); }}
function validateEmail($ema