PHP 错误与异常处理

良好的错误处理是健壮应用的基础,PHP 提供了完整的错误和异常处理机制。

错误级别

常量说明
E_ERROR致命错误,脚本终止
E_WARNING警告,脚本继续
E_NOTICE通知,轻微问题
E_DEPRECATED废弃功能警告
E_ALL所有错误
PHP 实例
// 开发环境:显示所有错误
error_reporting(E_ALL);
ini_set('display_errors', 1);

// 生产环境:记录错误,不显示 error_reporting(E_ALL); ini_set('display_errors', 0); ini_set('log_errors', 1); ini_set('error_log', '/var/log/php_errors.log'); ?> ``

异常处理

`php <?php function divide(float $a, float $b): float { if ($b === 0.0) { throw new InvalidArgumentException("除数不能为零"); } return $a / $b; }

try { echo divide(10, 2); // 5 echo divide(10, 0); // 抛出异常 } catch (InvalidArgumentException $e) { echo "参数错误:" . $e->getMessage(); } catch (Exception $e) { echo "未知错误:" . $e->getMessage(); } finally { echo "无论如何都会执行"; // 清理资源 } ?> `

自定义异常

`php <?php class AppException extends RuntimeException { public function __construct( string $message, private readonly string $context = '', int $code = 0, ?\Throwable $previous = null ) { parent::__construct($message, $code, $previous); }

public function getContext(): string { return $this->context; } }

class DatabaseException extends AppException {} class ValidationException extends AppException { private array $errors = [];

public function setErrors(array $errors): static { $this->errors = $errors; return $this; }

public function getErrors(): array { return $this->errors; } }

// 使用 try { $ex = new ValidationException("表单验证失败"); $ex->setErrors(["用户名不能为空", "邮箱格式错误"]); throw $ex; } catch (ValidationException $e) { foreach ($e->getErrors() as $err) { echo "- $err\n"; } } ?> `

全局异常处理器

`php <?php // 设置全局异常处理(捕获未被 catch 的异常) set_exception_handler(function (Throwable $e) { $message = sprintf( "[%s] %s in %s:%d\nStack trace:\n%s", date('Y-m-d H:i:s'), $e->getMessage(), $e->getFile(), $e->getLine(), $e->getTraceAsString() );

error_log($message);

// 生产环境显示友好页面 http_response_code(500); echo "服务器内部错误,请稍后重试。"; });

// 设置全局错误处理器 set_error_handler(function (int $errno, string $errstr, string $file, int $line): bool { if (!(error_reporting() & $errno)) return false; throw new ErrorException($errstr, 0, $errno, $file, $line); }); ?> `

异常链

`php <?php function connectDB(): void { try { // 模拟连接失败 throw new \RuntimeException("Connection refused"); } catch (\RuntimeException $e) { // 包装成业务异常,保留原始异常 throw new DatabaseException("数据库连接失败", 'db_connect', 500, $e); } }

try { connectDB(); } catch (DatabaseException $e) { echo $e->getMessage(); // 数据库连接失败 echo $e->getPrevious()->getMessage(); // Connection refused(原始原因) } ?> `

实用错误处理模式

`php <?php // Result 模式(避免异常滥用) class Result { private function __construct( private readonly bool $success, private readonly mixed $value, private readonly string $error = '' ) {}

public static function ok(mixed $value): static { return new static(true, $value); }

public static function fail(string $error): static { return new static(false, null, $error); }

public function isOk(): bool { return $this->success; } public function getValue(): mixed { return $this->value; } public function getError(): string { return $this->error; } }

function findUser(int $id): Result { if ($id <= 0) return Result::fail("ID 不合法"); // 模拟查询 return Result::ok(["id" => $id, "name" => "张三"]); }

$result = findUser(1); if ($result->isOk()) { echo $result->getValue()['name']; // 张三 } else { echo $result->getError(); } ?> `

日志记录

``php <?php // 简单日志函数 function logMessage(string $level, string $message, array $context = []): void { $line = sprintf( "[%s] [%s] %s %s\n", date('Y-m-d H:i:s'), strtoupper($level), $message, $context ? json_encode($context, JSON_UNESCAPED_UNICODE) : '' ); file_put_contents( __DIR__ . '/logs/app.log', $line, FILE_APPEND | LOCK_EX ); }

logMessage('info', '用户登录', ['user_id' => 1]); logMessage('error', '支付失败', ['order_id' => 'ORD-001', 'reason' => '余额不足']);