PHPerror_reporting()函数

简介

error_reporting() 是PHP内置的错误处理函数,用于设置或获取当前脚本的错误报告级别。它控制PHP应该报告哪些类型的错误,是调试和错误处理的重要工具。

这个函数既可以获取当前的错误报告级别,也可以设置新的错误报告级别。通过合理配置错误报告级别,可以在不同环境中控制错误信息的显示和记录。
注意:error_reporting() 只影响错误报告,不控制错误是否显示。要控制错误是否显示,需要使用 ini_set('display_errors', 1) 或修改php.ini。

语法

int error_reporting([int $level])

当传入参数时,设置错误报告级别并返回之前的值;不传参数时,返回当前错误报告级别。

参数

参数 类型 默认值 描述
$level int 可选 新的错误报告级别。可以是预定义常量或它们的组合。如果省略,函数返回当前错误报告级别。

返回值

int - 返回当前(或之前)的错误报告级别,以整数形式表示。

返回值是一个位掩码(bitmask),可以使用位运算符(|&~)来组合或排除特定错误类型。

错误级别常量

PHP定义了多个错误级别常量,可以单独使用或组合使用:

常量 描述 说明
1 E_ERROR 致命运行时错误 脚本会停止执行
2 E_WARNING 运行时警告 非致命错误,脚本继续执行
4 E_PARSE 编译时语法解析错误 由解析器生成
8 E_NOTICE 运行时通知 表示脚本遇到可能是个错误的情况
16 E_CORE_ERROR PHP初始化启动过程中的致命错误 PHP引擎启动时的错误
32 E_CORE_WARNING PHP初始化启动过程中的警告 PHP引擎启动时的警告
64 E_COMPILE_ERROR 编译时致命错误 由Zend脚本引擎生成
128 E_COMPILE_WARNING 编译时警告 由Zend脚本引擎生成
256 E_USER_ERROR 用户生成的错误 trigger_error()生成
512 E_USER_WARNING 用户生成的警告 trigger_error()生成
1024 E_USER_NOTICE 用户生成的通知 trigger_error()生成
2048 E_STRICT 运行时通知 PHP建议的代码修改,确保代码的兼容性
4096 E_RECOVERABLE_ERROR 可被捕捉的致命错误 可由用户定义的错误处理器捕捉
8192 E_DEPRECATED 运行时通知 警告代码在未来版本中可能无法工作
16384 E_USER_DEPRECATED 用户生成的弃用警告 trigger_error()生成
32767 E_ALL 所有错误和警告(PHP 5.4+) 包含除了E_STRICT之外的所有错误
注意:E_ALL的值在不同PHP版本中有所不同:
  • PHP 5.4及以上:32767(包含E_STRICT
  • PHP 5.3及以下:30719(不包含E_STRICT
要包含E_STRICT,可以使用E_ALL | E_STRICT

示例

示例1:基本用法 - 获取和设置错误级别

演示如何获取当前错误报告级别,并设置新的级别:

<?php
// 获取当前错误报告级别
$currentLevel = error_reporting();
echo "<div class='alert alert-info'>";
echo "当前错误报告级别: " . $currentLevel;
echo "</div>";

// 显示当前启用的错误类型
echo "<div style='background:#f8f9fa; padding:15px; border:1px solid #ddd; margin:10px 0;'>";
echo "<strong>当前启用的错误类型:</strong><br>";
displayErrorLevels($currentLevel);
echo "</div>";

// 设置新的错误报告级别 - 只显示错误和警告
$oldLevel = error_reporting(E_ERROR | E_WARNING | E_PARSE);
echo "<div class='alert alert-success'>";
echo "已设置新的错误级别: E_ERROR | E_WARNING | E_PARSE<br>";
echo "之前的值: " . $oldLevel;
echo "</div>";

// 测试错误报告
echo "<div style='background:#e7f3ff; padding:10px; border:1px solid #b3d7ff; margin:10px 0;'>";
echo "<strong>测试错误报告:</strong><br>";
// 这会触发警告(如果E_WARNING被启用)
echo $undefinedVariable;
echo "</div>";

// 关闭所有错误报告
error_reporting(0);
echo "<div class='alert alert-warning'>";
echo "已关闭所有错误报告";
echo "</div>";

// 重新测试 - 这次不会有错误显示
echo $undefinedVariable;

// 恢复原始设置
error_reporting($oldLevel);

// 辅助函数:显示启用的错误级别
function displayErrorLevels($level) {
    $errorConstants = [
        E_ERROR => 'E_ERROR',
        E_WARNING => 'E_WARNING',
        E_PARSE => 'E_PARSE',
        E_NOTICE => 'E_NOTICE',
        E_CORE_ERROR => 'E_CORE_ERROR',
        E_CORE_WARNING => 'E_CORE_WARNING',
        E_COMPILE_ERROR => 'E_COMPILE_ERROR',
        E_COMPILE_WARNING => 'E_COMPILE_WARNING',
        E_USER_ERROR => 'E_USER_ERROR',
        E_USER_WARNING => 'E_USER_WARNING',
        E_USER_NOTICE => 'E_USER_NOTICE',
        E_STRICT => 'E_STRICT',
        E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR',
        E_DEPRECATED => 'E_DEPRECATED',
        E_USER_DEPRECATED => 'E_USER_DEPRECATED',
    ];

    foreach ($errorConstants as $value => $name) {
        if ($level & $value) {
            echo "<span style='color:green;'>✓</span> " . $name . " (" . $value . ")<br>";
        } else {
            echo "<span style='color:red;'>✗</span> " . $name . " (" . $value . ")<br>";
        }
    }
}

示例2:常用的错误级别组合

展示一些常用的错误级别组合:

<?php
// 常用的错误级别组合
$errorLevels = [
    '关闭所有错误报告' => 0,
    '只显示致命错误' => E_ERROR,
    '显示错误和警告' => E_ERROR | E_WARNING,
    '显示错误、警告和通知' => E_ERROR | E_WARNING | E_NOTICE,
    '显示所有错误(PHP 5.4+)' => E_ALL,
    '显示所有错误(包含严格模式)' => E_ALL | E_STRICT,
    '开发环境推荐' => E_ALL,
    '生产环境推荐' => E_ERROR | E_WARNING | E_PARSE,
    '排除弃用警告' => E_ALL & ~E_DEPRECATED,
    '只显示用户错误' => E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE,
];

echo "<h4>常用的错误级别组合:</h4>";
echo "<table class='table table-bordered'>";
echo "<thead><tr><th>描述</th><th>值</th><th>代码示例</th></tr></thead>";
echo "<tbody>";

foreach ($errorLevels as $description => $level) {
    $codeExample = htmlspecialchars("error_reporting($level);");
    echo "<tr>";
    echo "<td>" . $description . "</td>";
    echo "<td>" . $level . "</td>";
    echo "<td><code>" . $codeExample . "</code></td>";
    echo "</tr>";
}

echo "</tbody></table>";

// 测试不同的错误级别
echo "<h4>测试不同的错误级别:</h4>";

// 1. 开发环境 - 显示所有错误
error_reporting(E_ALL);
ini_set('display_errors', 1);
echo "<div style='background:#e7f3ff; padding:10px; margin:10px 0; border:1px solid #b3d7ff;'>";
echo "<strong>开发环境设置 (E_ALL):</strong><br>";
// 这些都会显示
@$nonexistent;  // 静默错误
echo "</div>";

// 2. 生产环境 - 只显示重要错误
error_reporting(E_ERROR | E_WARNING | E_PARSE);
echo "<div style='background:#f8f9fa; padding:10px; margin:10px 0; border:1px solid #ddd;'>";
echo "<strong>生产环境设置 (E_ERROR | E_WARNING | E_PARSE):</strong><br>";
// 只有错误和警告会显示
@$nonexistent;  // 静默错误
echo "</div>";

// 3. 排除弃用警告
error_reporting(E_ALL & ~E_DEPRECATED);
echo "<div style='background:#fff3cd; padding:10px; margin:10px 0; border:1px solid #ffeaa7;'>";
echo "<strong>排除弃用警告 (E_ALL & ~E_DEPRECATED):</strong><br>";
echo "弃用警告将被隐藏";
echo "</div>";

示例3:在文件开头设置错误报告

在应用程序入口点设置错误报告:

<?php
// application/bootstrap.php

// 根据环境设置错误报告
function setupErrorReporting() {
    // 定义应用环境
    $environment = getenv('APP_ENV') ?: 'production';

    if ($environment === 'development' || $environment === 'testing') {
        // 开发环境 - 显示所有错误
        error_reporting(E_ALL);
        ini_set('display_errors', 1);
        ini_set('display_startup_errors', 1);
        ini_set('log_errors', 1);
        ini_set('error_log', __DIR__ . '/../logs/development.log');
    } else {
        // 生产环境 - 不显示错误,但记录到日志
        error_reporting(E_ERROR | E_WARNING | E_PARSE);
        ini_set('display_errors', 0);
        ini_set('display_startup_errors', 0);
        ini_set('log_errors', 1);
        ini_set('error_log', __DIR__ . '/../logs/production.log');
    }

    // 设置自定义错误处理器
    set_error_handler('customErrorHandler');

    // 设置异常处理器
    set_exception_handler('customExceptionHandler');

    // 注册关闭函数以捕获致命错误
    register_shutdown_function('shutdownHandler');
}

// 调用设置函数
setupErrorReporting();

// 模拟自定义错误处理器
function customErrorHandler($errno, $errstr, $errfile, $errline) {
    // 记录错误到文件
    $logMessage = sprintf(
        "[%s] [%s] %s in %s on line %d\n",
        date('Y-m-d H:i:s'),
        getErrorTypeName($errno),
        $errstr,
        $errfile,
        $errline
    );

    error_log($logMessage, 3, 'error.log');

    // 如果环境是开发,显示错误
    if (getenv('APP_ENV') === 'development') {
        echo "<div style='background:#f8d7da; border:1px solid #f5c6cb; padding:10px; margin:10px 0;'>";
        echo "<strong>错误:</strong> " . htmlspecialchars($errstr) . "<br>";
        echo "<strong>位置:</strong> " . $errfile . " 第 " . $errline . " 行";
        echo "</div>";
    }

    // 不要执行PHP内置错误处理器
    return true;
}

function customExceptionHandler($exception) {
    // 处理未捕获的异常
    error_log("未捕获异常: " . $exception->getMessage(), 3, 'error.log');
}

function shutdownHandler() {
    $error = error_get_last();
    if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
        error_log("致命错误: " . $error['message'], 3, 'error.log');
    }
}

function getErrorTypeName($type) {
    $errorTypes = [
        1 => 'E_ERROR',
        2 => 'E_WARNING',
        8 => 'E_NOTICE',
        256 => 'E_USER_ERROR',
        512 => 'E_USER_WARNING',
        1024 => 'E_USER_NOTICE',
        4096 => 'E_RECOVERABLE_ERROR',
        8192 => 'E_DEPRECATED',
        16384 => 'E_USER_DEPRECATED',
    ];

    return $errorTypes[$type] ?? "UNKNOWN($type)";
}

echo "<div class='alert alert-success'>";
echo "错误报告已根据环境配置: " . (getenv('APP_ENV') ?: 'production');
echo "</div>";

示例4:临时修改错误级别

在特定代码块中临时修改错误报告级别:

<?php
// 保存当前错误级别
$originalErrorLevel = error_reporting();

echo "<div class='alert alert-info'>";
echo "原始错误级别: " . $originalErrorLevel;
echo "</div>";

// 示例1:临时关闭错误报告
echo "<h4>1. 临时关闭错误报告:</h4>";

// 保存当前级别
$previousLevel = error_reporting(0);

// 执行可能产生错误的代码
$result = @file_get_contents('non_existent_file.txt');  // 使用@抑制错误
if ($result === false) {
    echo "<div style='background:#f8f9fa; padding:10px; margin:10px 0;'>";
    echo "文件读取失败,但错误被抑制";
    echo "</div>";
}

// 恢复之前的级别
error_reporting($previousLevel);

// 示例2:临时开启调试模式
echo "<h4>2. 临时开启所有错误报告:</h4>";

$previousLevel = error_reporting(E_ALL);
ini_set('display_errors', 1);

// 执行调试代码
echo "<div style='background:#e7f3ff; padding:10px; border:1px solid #b3d7ff;'>";
echo "<strong>调试信息:</strong><br>";
$debugVar = "调试变量";
echo $undefinedVar;  // 这会显示Notice
echo "</div>";

// 恢复之前的级别
error_reporting($previousLevel);
ini_set('display_errors', 0);

// 示例3:使用try-catch控制错误级别
echo "<h4>3. 在try-catch块中控制错误级别:</h4>";

function safelyExecute($callback) {
    // 保存当前错误级别
    $oldLevel = error_reporting(0);
    $oldDisplayErrors = ini_get('display_errors');
    ini_set('display_errors', 0);

    try {
        $result = $callback();
        return ['success' => true, 'result' => $result];
    } catch (Exception $e) {
        return ['success' => false, 'error' => $e->getMessage()];
    } finally {
        // 无论是否发生异常,都恢复原始设置
        error_reporting($oldLevel);
        ini_set('display_errors', $oldDisplayErrors);
    }
}

// 测试安全执行
$result = safelyExecute(function() {
    // 这里可能产生错误
    return file_get_contents('non_existent_file.txt');
});

echo "<div style='background:" . ($result['success'] ? '#d4edda' : '#f8d7da') . "; padding:10px; border:1px solid " . ($result['success'] ? '#c3e6cb' : '#f5c6cb') . ";'>";
echo "<strong>执行结果:</strong> ";
if ($result['success']) {
    echo "成功";
} else {
    echo "失败: " . htmlspecialchars($result['error']);
}
echo "</div>";

// 恢复原始设置
error_reporting($originalErrorLevel);

示例5:错误级别掩码操作

使用位运算符操作错误级别掩码:

<?php
// 初始错误级别
error_reporting(E_ALL);
$currentLevel = error_reporting();

echo "<div class='alert alert-info'>";
echo "初始错误级别: " . $currentLevel;
echo "</div>";

// 1. 添加错误类型
echo "<h4>1. 添加错误类型:</h4>";

// 添加E_DEPRECATED到当前级别
$newLevel = error_reporting($currentLevel | E_DEPRECATED);
echo "<div style='background:#e7f3ff; padding:10px; margin:10px 0;'>";
echo "添加E_DEPRECATED: " . error_reporting() . "<br>";
echo "之前的级别: " . $newLevel;
echo "</div>";

// 2. 移除错误类型
echo "<h4>2. 移除错误类型:</h4>";

// 从当前级别移除E_NOTICE
$currentLevel = error_reporting();
$newLevel = error_reporting($currentLevel & ~E_NOTICE);
echo "<div style='background:#fff3cd; padding:10px; margin:10px 0;'>";
echo "移除E_NOTICE: " . error_reporting() . "<br>";
echo "之前的级别: " . $newLevel;
echo "</div>";

// 3. 检查是否包含特定错误类型
echo "<h4>3. 检查是否包含特定错误类型:</h4>";

function isErrorTypeEnabled($errorType) {
    $currentLevel = error_reporting();
    return ($currentLevel & $errorType) === $errorType;
}

$errorTypes = [
    'E_ERROR' => E_ERROR,
    'E_WARNING' => E_WARNING,
    'E_NOTICE' => E_NOTICE,
    'E_DEPRECATED' => E_DEPRECATED,
    'E_STRICT' => E_STRICT,
];

echo "<table class='table table-bordered'>";
echo "<thead><tr><th>错误类型</th><th>是否启用</th></tr></thead>";
echo "<tbody>";

foreach ($errorTypes as $name => $type) {
    $enabled = isErrorTypeEnabled($type) ? '是' : '否';
    $color = isErrorTypeEnabled($type) ? 'green' : 'red';
    echo "<tr>";
    echo "<td>" . $name . "</td>";
    echo "<td style='color:" . $color . ";'><strong>" . $enabled . "</strong></td>";
    echo "</tr>";
}

echo "</tbody></table>";

// 4. 切换错误类型(开启/关闭)
echo "<h4>4. 切换错误类型:</h4>";

function toggleErrorType($errorType) {
    $currentLevel = error_reporting();

    if (($currentLevel & $errorType) === $errorType) {
        // 如果已启用,则关闭
        error_reporting($currentLevel & ~$errorType);
        return "已关闭";
    } else {
        // 如果已禁用,则开启
        error_reporting($currentLevel | $errorType);
        return "已开启";
    }
}

// 切换E_NOTICE
$result = toggleErrorType(E_NOTICE);
echo "<div class='alert " . ($result === '已开启' ? 'alert-success' : 'alert-warning') . "'>";
echo "E_NOTICE: " . $result;
echo "</div>";

// 5. 创建自定义错误级别组合
echo "<h4>5. 自定义错误级别组合:</h4>";

// 只显示用户错误,排除弃用警告
$customLevel = E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE;
$customLevel &= ~E_DEPRECATED;  // 排除弃用警告
$customLevel &= ~E_USER_DEPRECATED;  // 排除用户弃用警告

error_reporting($customLevel);
echo "<div style='background:#d1ecf1; padding:10px; border:1px solid #bee5eb;'>";
echo "自定义错误级别: " . error_reporting();
echo "</div>";

示例6:完整的环境配置类

创建一个完整的错误报告配置类:

<?php
/**
 * 错误报告配置类
 */
class ErrorReportingConfig {
    private static $environments = [
        'development' => [
            'error_reporting' => E_ALL,
            'display_errors' => 1,
            'display_startup_errors' => 1,
            'log_errors' => 1,
            'error_log' => 'logs/development.log',
        ],
        'testing' => [
            'error_reporting' => E_ALL,
            'display_errors' => 1,
            'display_startup_errors' => 1,
            'log_errors' => 1,
            'error_log' => 'logs/testing.log',
        ],
        'staging' => [
            'error_reporting' => E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING,
            'display_errors' => 0,
            'display_startup_errors' => 0,
            'log_errors' => 1,
            'error_log' => 'logs/staging.log',
        ],
        'production' => [
            'error_reporting' => E_ERROR | E_WARNING | E_PARSE,
            'display_errors' => 0,
            'display_startup_errors' => 0,
            'log_errors' => 1,
            'error_log' => 'logs/production.log',
        ],
    ];

    /**
     * 配置错误报告
     */
    public static function configure($environment = null) {
        if ($environment === null) {
            $environment = self::detectEnvironment();
        }

        if (!isset(self::$environments[$environment])) {
            throw new InvalidArgumentException("未知的环境: " . $environment);
        }

        $config = self::$environments[$environment];

        // 应用配置
        error_reporting($config['error_reporting']);
        ini_set('display_errors', $config['display_errors']);
        ini_set('display_startup_errors', $config['display_startup_errors']);
        ini_set('log_errors', $config['log_errors']);

        if (!empty($config['error_log'])) {
            // 确保日志目录存在
            $logDir = dirname($config['error_log']);
            if (!is_dir($logDir)) {
                mkdir($logDir, 0755, true);
            }
            ini_set('error_log', $config['error_log']);
        }

        return [
            'environment' => $environment,
            'config' => $config,
        ];
    }

    /**
     * 检测环境
     */
    private static function detectEnvironment() {
        // 1. 检查环境变量
        if (getenv('APP_ENV')) {
            return getenv('APP_ENV');
        }

        // 2. 检查HTTP_HOST(Web环境)
        if (isset($_SERVER['HTTP_HOST'])) {
            $host = $_SERVER['HTTP_HOST'];

            if (strpos($host, 'localhost') !== false ||
                strpos($host, '127.0.0.1') !== false ||
                strpos($host, 'dev.') === 0 ||
                strpos($host, 'test.') === 0) {
                return 'development';
            }

            if (strpos($host, 'staging.') === 0 ||
                strpos($host, 'qa.') === 0) {
                return 'staging';
            }
        }

        // 3. 默认生产环境
        return 'production';
    }

    /**
     * 获取当前配置
     */
    public static function getCurrentConfig() {
        return [
            'error_reporting' => error_reporting(),
            'display_errors' => ini_get('display_errors'),
            'display_startup_errors' => ini_get('display_startup_errors'),
            'log_errors' => ini_get('log_errors'),
            'error_log' => ini_get('error_log'),
        ];
    }

    /**
     * 显示当前配置
     */
    public static function displayCurrentConfig() {
        $config = self::getCurrentConfig();

        $output = "<div style='background:#f8f9fa; padding:15px; border:1px solid #ddd;'>";
        $output .= "<h4>当前错误报告配置:</h4>";
        $output .= "<table class='table table-sm table-bordered'>";

        foreach ($config as $key => $value) {
            $output .= "<tr>";
            $output .= "<td><strong>" . $key . "</strong></td>";
            $output .= "<td>" . htmlspecialchars($value) . "</td>";
            $output .= "</tr>";
        }

        $output .= "</table>";
        $output .= "</div>";

        return $output;
    }
}

// 使用示例
echo "<h4>自动检测并配置环境:</h4>";

// 自动检测环境并配置
$config = ErrorReportingConfig::configure();

echo "<div class='alert alert-success'>";
echo "已配置为: " . $config['environment'] . " 环境";
echo "</div>";

// 显示当前配置
echo ErrorReportingConfig::displayCurrentConfig();

// 测试不同环境
echo "<h4>手动设置不同环境:</h4>";

$environments = ['development', 'testing', 'staging', 'production'];
foreach ($environments as $env) {
    try {
        ErrorReportingConfig::configure($env);
        echo "<div class='alert alert-info'>";
        echo "<strong>" . ucfirst($env) . "环境:</strong> ";
        echo "错误报告级别: " . error_reporting();
        echo "</div>";
    } catch (Exception $e) {
        echo "<div class='alert alert-danger'>" . $e->getMessage() . "</div>";
    }
}

// 恢复为自动检测的环境
ErrorReportingConfig::configure();

最佳实践

开发环境

设置:E_ALLE_ALL | E_STRICT

目的:捕获所有可能的错误和警告,便于调试

error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
生产环境

设置:E_ERROR | E_WARNING | E_PARSE

目的:只显示关键错误,记录日志但不显示给用户

error_reporting(E_ERROR | E_WARNING | E_PARSE);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', '/path/to/error.log');
临时调试

技巧:在需要调试的代码块前后临时修改错误级别

$oldLevel = error_reporting(E_ALL);
// 调试代码
error_reporting($oldLevel);
错误过滤

技巧:使用位运算符过滤特定类型的错误

// 排除弃用警告
error_reporting(E_ALL & ~E_DEPRECATED);

// 只显示用户错误
error_reporting(E_USER_ERROR | E_USER_WARNING);

注意事项

  • display_errors vs error_reporting: error_reporting()控制报告哪些错误,display_errors控制是否显示错误,两者需要配合使用
  • 运行时设置:有些错误(如解析错误、编译错误)发生在脚本运行之前,无法通过error_reporting()控制
  • @操作符:使用@错误控制运算符可以临时抑制错误,不受error_reporting()影响
  • 性能影响:较高的错误报告级别可能会轻微影响性能,因为需要检查更多类型的错误
  • 安全性:在生产环境中永远不要显示错误给用户,错误信息可能泄露敏感数据
  • PHP版本差异:E_ALL的值在不同PHP版本中不同,使用E_ALL | E_STRICT确保包含所有错误