PHP 提供錯誤與異常雙重機制處理異常情況。錯誤屬於引擎級別(不可捕獲的致命錯誤除外),異常屬於應用級別(可捕獲、可控制流)。正確配置與使用是構建健壯應用的基石。
| 指令 | 開發環境 | 生產環境 | 說明 |
|---|---|---|---|
error_reporting | E_ALL | E_ALL & ~E_DEPRECATED & ~E_STRICT | 報告級別 |
display_errors | On | Off | 瀏覽器顯示 |
log_errors | On | On | 寫入日誌 |
error_log | /var/log/php_errors.log | /var/log/php_errors.log | 日誌路徑 |
track_errors | On | Off | $php_errormsg (已棄用) |
<?php
// 開發環境
ini_set('error_reporting', E_ALL);
ini_set('display_errors', '1');
ini_set('log_errors', '1');
ini_set('error_log', __DIR__ . '/logs/php_errors.log');
// 生產環境
ini_set('error_reporting', E_ALL & ~E_DEPRECATED & ~E_STRICT);
ini_set('display_errors', '0');
ini_set('log_errors', '1');
ini_set('error_log', '/var/log/php/php_errors.log');
?>

<?php
function customErrorHandler(int $errno, string $errstr, string $errfile, int $errline, array $errcontext = []) {
// 忽略未啟用的錯誤級別
if (!(error_reporting() & $errno)) return false;
$msg = "[{$errno}] {$errstr} in {$errfile}:{$errline}";
error_log($msg . "\n", 3, '/var/log/php/custom_errors.log');
// 開發環境顯示
if (ini_get('display_errors')) {
echo "{$msg}";
}
return true; // 阻止內建處理器
}
set_error_handler('customErrorHandler', E_ALL & ~E_DEPRECATED & ~E_STRICT);
?>
<?php
try {
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$id]);
$user = $stmt->fetch();
if (!$user) {
throw new DomainException("用戶不存在: {$id}");
}
} catch (PDOException $e) {
error_log("DB Error: {$e->getMessage()}");
throw new RuntimeException('服務暫時不可用', 503, $e);
} catch (DomainException $e) {
http_response_code(404);
echo $e->getMessage();
} finally {
// 清理資源
}
?>
<?php
function errorToException(int $errno, string $errstr, string $errfile, int $errline) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler('errorToException', E_ALL);
try {
$x = 1 / 0; // Warning: Division by zero → ErrorException
} catch (ErrorException $e) {
echo "捕獲: {$e->getMessage()}";
}
?>
<?php
// PHP 7+ 可捕獲 TypeError, ParseError, ArithmeticError 等
try {
$fn = function(int $x) { return $x; };
$fn('not int'); // TypeError
} catch (TypeError $e) {
echo "類型錯誤: {$e->getMessage()}";
}
// 統一捕獲所有可拋出物件
try {
// ...
} catch (Throwable $e) { // Error + Exception 共同父介面
error_log("致命: {$e->getMessage()}\n{$e->getTraceAsString()}");
}
?>
<?php
// error_get_last():最後發生的錯誤 (含致命錯誤)
register_shutdown_function(function() {
$error = error_get_last();
if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR])) {
error_log("致命錯誤: {$error['message']} in {$error['file']}:{$error['line']}");
}
});
// $php_errormsg (需 track_errors=On,PHP 8.0 棄用)
@$fp = fopen('nonexistent', 'r');
echo $php_errormsg; // 最後一個錯誤訊息
?>
throw new DomainException()、try-catch 控制流display_errors=Off、log_errors=OnDomainException (業務)、RuntimeException (系統)、InvalidArgumentException (參數)throw new ...(prev: $e)$php_errormsg錯誤與異常機制互補,配置得當能讓開發期快速定位、生產期靜默記錄、業務邏輯可控異常流,是專業 PHP 應用的標配。