set_error_handler

(PHP 4 >= 4.0.1, PHP 5, PHP 7, PHP 8)

set_error_handler设置用户定义的错误处理函数

描述

set_error_handler(?callable $callback, int $error_levels = E_ALL): ?callable

设置用户函数(callback)来处理脚本中的错误。

此函数可用于在运行时定义自定义错误处理程序,例如在需要在发生严重错误时进行文件/数据清理的应用程序中,或者在响应某些条件(使用 trigger_error())时触发错误。

重要的是要记住,除非回调函数返回 false,否则标准 PHP 错误处理程序将完全绕过 error_levels 指定的错误类型。 error_reporting() 设置将不起作用,并且无论如何都会调用错误处理程序 - 但是,仍然可以读取 error_reporting 的当前值并采取相应措施。

另请注意,如果需要,处理程序有责任通过调用 exit() 来停止脚本执行。如果错误处理函数返回,脚本执行将继续执行导致错误的语句后的下一条语句。

以下错误类型无法使用用户定义函数处理:E_ERRORE_PARSEE_CORE_ERRORE_CORE_WARNINGE_COMPILE_ERRORE_COMPILE_WARNING,无论它们在何处引发,以及大多数在调用 set_error_handler() 的文件中引发的 E_STRICT

如果在脚本执行之前发生错误(例如在文件上传时),则无法调用自定义错误处理程序,因为它此时尚未注册。

参数

callback

如果传递了 null,则处理程序将重置为其默认状态。否则,处理程序是一个具有以下签名的回调

handler(
    int $errno,
    string $errstr,
    string $errfile = ?,
    int $errline = ?,
    array $errcontext = ?
): bool
errno
第一个参数 errno 将传递引发的错误级别,作为一个整数。
errstr
第二个参数 errstr 将传递错误消息,作为一个字符串。
errfile
如果回调接受第三个参数 errfile,它将传递引发错误的文件名,作为一个字符串。
errline
如果回调接受第四个参数 errline,它将传递引发错误的行号,作为一个整数。
errcontext
如果回调接受第五个参数 errcontext,它将传递一个指向错误发生时活动符号表的数组。换句话说,errcontext 将包含一个数组,其中包含错误触发时在作用域中存在的每个变量。用户错误处理程序不得修改错误上下文。
警告

此参数自 PHP 7.2.0 起已弃用,自 PHP 8.0.0 起已删除。如果函数在没有默认值的情况下定义了此参数,则在调用它时将引发“参数太少”错误。

如果函数返回 false,则正常错误处理程序将继续。

error_levels

可用于屏蔽 callback 函数的触发,就像 error_reporting ini 设置控制显示哪些错误一样。如果没有设置此掩码,则无论 error_reporting 设置如何,都会为每个错误调用 callback

返回值

返回先前定义的错误处理程序(如果有)。如果使用内置错误处理程序,则返回 null。如果先前的错误处理程序是类方法,则此函数将返回一个包含类和方法名的索引数组。

变更日志

版本 描述
8.0.0 errcontext 已删除,不再传递给用户回调。
7.2.0 errcontext 已弃用。现在使用此参数会发出 E_DEPRECATED 通知。

示例

示例 #1 使用 set_error_handler()trigger_error() 进行错误处理

下面的示例演示了通过触发错误并使用用户定义函数处理它们来处理内部异常

<?php
// 错误处理函数
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
if (!(
error_reporting() & $errno)) {
// 此错误代码未包含在 error_reporting 中,因此让它传递给标准 PHP 错误处理程序
return false;
}

// $errstr 可能需要转义:
$errstr = htmlspecialchars($errstr);

switch (
$errno) {
case
E_USER_ERROR:
echo
"<b>我的错误</b> [$errno] $errstr<br />\n";
echo
"致命错误出现在文件 $errfile 的第 $errline 行";
echo
", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
echo
"正在中止...<br />\n";
exit(
1);

case
E_USER_WARNING:
echo
"<b>我的警告</b> [$errno] $errstr<br />\n";
break;

case
E_USER_NOTICE:
echo
"<b>我的提示</b> [$errno] $errstr<br />\n";
break;

default:
echo
"未知错误类型: [$errno] $errstr<br />\n";
break;
}

/* 不要执行 PHP 内部错误处理程序 */
return true;
}

// 测试错误处理的函数
function scale_by_log($vect, $scale)
{
if (!
is_numeric($scale) || $scale <= 0) {
trigger_error("log(x) 当 x <= 0 时未定义,您使用了:scale = $scale", E_USER_ERROR);
}

if (!
is_array($vect)) {
trigger_error("输入向量不正确,期望值为数组", E_USER_WARNING);
return
null;
}

$temp = array();
foreach(
$vect as $pos => $value) {
if (!
is_numeric($value)) {
trigger_error("位置 $pos 的值不是数字,使用 0(零)", E_USER_NOTICE);
$value = 0;
}
$temp[$pos] = log($scale) * $value;
}

return
$temp;
}

// 设置为用户定义的错误处理程序
$old_error_handler = set_error_handler("myErrorHandler");

// 触发一些错误,首先定义一个包含非数字项目的混合数组
echo "向量 a\n";
$a = array(2, 3, "foo", 5.5, 43.3, 21.11);
print_r($a);

// 现在生成第二个数组
echo "----\n向量 b - 一个提示 (b = log(PI) * a)\n";
/* 位置 $pos 的值不是数字,使用 0(零) */
$b = scale_by_log($a, M_PI);
print_r($b);

// 这是个问题,我们传递了一个字符串而不是一个数组
echo "----\n向量 c - 一个警告\n";
/* 输入向量不正确,期望值为数组 */
$c = scale_by_log("不是数组", 2.3);
var_dump($c); // NULL

// 这是一个严重错误,零或负数的对数未定义
echo "----\n向量 d - 致命错误\n";
/* log(x) 当 x <= 0 时未定义,您使用了:scale = $scale" */
$d = scale_by_log($a, -2.5);
var_dump($d); // 永远不会到达
?>

上面的例子将输出类似于以下内容

vector a
Array
(
    [0] => 2
    [1] => 3
    [2] => foo
    [3] => 5.5
    [4] => 43.3
    [5] => 21.11
)
----
vector b - a notice (b = log(PI) * a)
<b>My NOTICE</b> [1024] Value at position 2 is not a number, using 0 (zero)<br />
Array
(
    [0] => 2.2894597716988
    [1] => 3.4341896575482
    [2] => 0
    [3] => 6.2960143721717
    [4] => 49.566804057279
    [5] => 24.165247890281
)
----
vector c - a warning
<b>My WARNING</b> [512] Incorrect input vector, array of values expected<br />
NULL
----
vector d - fatal error
<b>My ERROR</b> [256] log(x) for x <= 0 is undefined, you used: scale = -2.5<br />
  Fatal error on line 35 in file trigger_error.php, PHP 5.2.1 (FreeBSD)<br />
Aborting...<br />

参见

添加一个备注

用户贡献的备注 34 备注

Philip
11 年前
仅靠此函数,您无法捕获致命错误,有一个简单的解决方法。以下是我的 error.php 文件的一部分,它处理应用程序中的错误和异常。在有人抱怨之前,我会补充一点,我不在乎我是否使用全局变量,此文件是我小型框架的一部分,如果没有“config”变量,应用程序将会崩溃。

<?php

/**
* 错误处理程序,将流程传递给异常日志记录器,并使用新的 ErrorException。
*/
function log_error( $num, $str, $file, $line, $context = null )
{
log_exception( new ErrorException( $str, 0, $num, $file, $line ) );
}

/**
* 未捕获异常处理程序。
*/
function log_exception( Exception $e )
{
global
$config;

if (
$config["debug"] == true )
{
print
"<div style='text-align: center;'>";
print
"<h2 style='color: rgb(190, 50, 50);'>发生异常:</h2>";
print
"<table style='width: 800px; display: inline-block;'>";
print
"<tr style='background-color:rgb(230,230,230);'><th style='width: 80px;'>类型</th><td>" . get_class( $e ) . "</td></tr>";
print
"<tr style='background-color:rgb(240,240,240);'><th>消息</th><td>{$e->getMessage()}</td></tr>";
print
"<tr style='background-color:rgb(230,230,230);'><th>文件</th><td>{$e->getFile()}</td></tr>";
print
"<tr style='background-color:rgb(240,240,240);'><th>行号</th><td>{$e->getLine()}</td></tr>";
print
"</table></div>";
}
else
{
$message = "类型: " . get_class( $e ) . "; 消息: {$e->getMessage()}; 文件: {$e->getFile()}; 行号: {$e->getLine()};";
file_put_contents( $config["app_dir"] . "/tmp/logs/exceptions.log", $message . PHP_EOL, FILE_APPEND );
header( "Location: {$config["error_page"]}" );
}

exit();
}

/**
* 检查致命错误,解决 set_error_handler 在致命错误上不起作用的问题。
*/
function check_for_fatal()
{
$error = error_get_last();
if (
$error["type"] == E_ERROR )
log_error( $error["type"], $error["message"], $error["file"], $error["line"] );
}

register_shutdown_function( "check_for_fatal" );
set_error_handler( "log_error" );
set_exception_handler( "log_exception" );
ini_set( "display_errors", "off" );
error_reporting( E_ALL );
elad dot yosifon at gmail dot com
11 年前
<?php
/**
* 基于 E_* 错误类型的抛出异常
*/
set_error_handler(function ($err_severity, $err_msg, $err_file, $err_line, array $err_context)
{
// 错误被 @ 运算符抑制了
if (0 === error_reporting()) { return false;}
switch(
$err_severity)
{
case
E_ERROR: throw new ErrorException ($err_msg, 0, $err_severity, $err_file, $err_line);
case
E_WARNING: throw new WarningException ($err_msg, 0, $err_severity, $err_file, $err_line);
case
E_PARSE: throw new ParseException ($err_msg, 0, $err_severity, $err_file, $err_line);
case
E_NOTICE: throw new NoticeException ($err_msg, 0, $err_severity, $err_file, $err_line);
case
E_CORE_ERROR: throw new CoreErrorException ($err_msg, 0, $err_severity, $err_file, $err_line);
case
E_CORE_WARNING: throw new CoreWarningException ($err_msg, 0, $err_severity, $err_file, $err_line);
case
E_COMPILE_ERROR: throw new CompileErrorException ($err_msg, 0, $err_severity, $err_file, $err_line);
case
E_COMPILE_WARNING: throw new CoreWarningException ($err_msg, 0, $err_severity, $err_file, $err_line);
case
E_USER_ERROR: throw new UserErrorException ($err_msg, 0, $err_severity, $err_file, $err_line);
case
E_USER_WARNING: throw new UserWarningException ($err_msg, 0, $err_severity, $err_file, $err_line);
case
E_USER_NOTICE: throw new UserNoticeException ($err_msg, 0, $err_severity, $err_file, $err_line);
case
E_STRICT: throw new StrictException ($err_msg, 0, $err_severity, $err_file, $err_line);
case
E_RECOVERABLE_ERROR: throw new RecoverableErrorException ($err_msg, 0, $err_severity, $err_file, $err_line);
case
E_DEPRECATED: throw new DeprecatedException ($err_msg, 0, $err_severity, $err_file, $err_line);
case
E_USER_DEPRECATED: throw new UserDeprecatedException ($err_msg, 0, $err_severity, $err_file, $err_line);
}
});

class
WarningException extends ErrorException {}
class
ParseException extends ErrorException {}
class
NoticeException extends ErrorException {}
class
CoreErrorException extends ErrorException {}
class
CoreWarningException extends ErrorException {}
class
CompileErrorException extends ErrorException {}
class
CompileWarningException extends ErrorException {}
class
UserErrorException extends ErrorException {}
class
UserWarningException extends ErrorException {}
class
UserNoticeException extends ErrorException {}
class
StrictException extends ErrorException {}
class
RecoverableErrorException extends ErrorException {}
class
DeprecatedException extends ErrorException {}
class
UserDeprecatedException extends ErrorException {}
aditycse at gmail dot com
8 年前
<?php
/**
* 用于在错误报告设置且 display_errors 关闭时将所有 php 通知、警告等记录到文件中
* @uses 用于生产环境中,将所有类型的 php 代码错误记录到文件中,以便进一步调试
* 和代码性能
* @author Aditya Mehrotra<[email protected]>
*/
error_reporting(E_ALL);
ini_set("display_errors", "off");
define('ERROR_LOG_FILE', '/var/www/error.log');

/**
* 自定义错误处理程序
* @param integer $code
* @param string $description
* @param string $file
* @param interger $line
* @param mixed $context
* @return boolean
*/
function handleError($code, $description, $file = null, $line = null, $context = null) {
$displayErrors = ini_get("display_errors");
$displayErrors = strtolower($displayErrors);
if (
error_reporting() === 0 || $displayErrors === "on") {
return
false;
}
list(
$error, $log) = mapErrorCode($code);
$data = array(
'level' => $log,
'code' => $code,
'error' => $error,
'description' => $description,
'file' => $file,
'line' => $line,
'context' => $context,
'path' => $file,
'message' => $error . ' (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']'
);
return
fileLog($data);
}

/**
* 此方法用于将数据写入文件
* @param mixed $logData
* @param string $fileName
* @return boolean
*/
function fileLog($logData, $fileName = ERROR_LOG_FILE) {
$fh = fopen($fileName, 'a+');
if (
is_array($logData)) {
$logData = print_r($logData, 1);
}
$status = fwrite($fh, $logData);
fclose($fh);
return (
$status) ? true : false;
}

/**
* 将错误代码映射到错误词和日志位置。
*
* @param int $code 要映射的错误代码
* @return array 错误词和日志位置的数组。
*/
function mapErrorCode($code) {
$error = $log = null;
switch (
$code) {
case
E_PARSE:
case
E_ERROR:
case
E_CORE_ERROR:
case
E_COMPILE_ERROR:
case
E_USER_ERROR:
$error = '致命错误';
$log = LOG_ERR;
break;
case
E_WARNING:
case
E_USER_WARNING:
case
E_COMPILE_WARNING:
case
E_RECOVERABLE_ERROR:
$error = '警告';
$log = LOG_WARNING;
break;
case
E_NOTICE:
case
E_USER_NOTICE:
$error = '通知';
$log = LOG_NOTICE;
break;
case
E_STRICT:
$error = '严格';
$log = LOG_NOTICE;
break;
case
E_DEPRECATED:
case
E_USER_DEPRECATED:
$error = '已弃用';
$log = LOG_NOTICE;
break;
default :
break;
}
return array(
$error, $log);
}

// 调用自定义错误处理程序
set_error_handler("handleError");

print_r($arra); // 未定义变量
print_r($dssdfdfgg); // 未定义变量
include_once 'file.php'; // 没有此文件或目录
?>
steve962 at gmail dot com
6 年前
使用此函数的返回值时要小心。因为它返回旧的处理程序,您可能很想这样做

<?php
function do_something()
{
$old = set_error_handler(“my_error_handler”);
// 执行要由 my_error_handler 处理的操作
set_error_handler($old);
}
?>

这将起作用,但它会咬你,因为每次你这样做时,它都会导致内存泄漏,因为旧的错误处理程序被放在一个堆栈中,供 restore_error_handler() 函数使用。

因此,始终使用该函数来恢复旧的错误处理程序

<?php
function do_something()
{
set_error_handler(“my_error_handler”);
// 执行要由 my_error_handler 处理的操作
restore_error_handler();
}
?>
dannykopping at gmail dot com
10 年前
请记住,当尝试在 PHP >= 5.3 中对命名空间类设置静态定义的错误处理程序时,您需要使用类命名空间

<?php
set_error_handler
('\\My\\Namespace\\Bob::errorHandler');
?>
nizamgok at gmail dot com
15 年前
我意识到这里有些人提到您无法捕获解析错误(类型 4,E_PARSE)。这不是真的。这是我的做法。我希望这对某人有所帮助。

1) 在 web 根目录中创建一个“auto_prepend.php”文件,并添加以下内容

<?php
register_shutdown_function
('error_alert');

function
error_alert()
{
if(
is_null($e = error_get_last()) === false)
{
mail('[email protected]', 'Error from auto_prepend', print_r($e, true));
}
}
?>

2) 然后将此“php_value auto_prepend_file /www/auto_prepend.php”添加到 web 根目录中的 .htaccess 文件中。

* 确保您更改了电子邮件地址和文件路径。
Jacob Slomp
11 年前
如果您不希望您的客户看到错误,并且您确实希望比他们领先一步,这可能很方便。

即使是解析错误,它也会通过电子邮件将错误发送给您。

set_error_handler() 不适用于我想要的东西。

<?php
ini_set
('log_errors',TRUE);
ini_set('error_log','tiny_uploads/errors.txt');

if(
$_SERVER['REMOTE_ADDR'] != "YOUR IP ADDRESS"){
ini_set('display_errors',false);
}

function
byebye(){

$dir = dirname(__FILE__);
if(
file_exists($dir."/tiny_uploads/errors.txt")){

$errors = file_get_contents($dir."/tiny_uploads/errors.txt");

if(
trim($errors)){

$head = "From: php_errors@".str_replace('www.','',$_SERVER['HTTP_HOST'])."\r\n";

$errors .= "---------------------------------------------\n\n";

$errors .= "\n\nServer Info:\n\n".print_r($_SERVER, 1)."\n\n";
$errors .= "---------------------------------------------\n\n";

$errors .= "\n\nCOOKIE:\n\n".print_r($_COOKIE, 1)."\n\n";
$errors .= "---------------------------------------------\n\n";

$errors .= "\n\nPOST:\n\n".print_r($_POST, 1)."\n\n";
$errors .= "---------------------------------------------\n\n";

$errors .= "\n\nGET:\n\n".print_r($_GET, 1)."\n\n";


mail("[email protected]","PHP Error ".$_SERVER['HTTP_HOST']."", $errors , $head);

$fp = fopen($dir."/tiny_uploads/errors.txt","w+");
fputs($fp, "");
fclose($fp);
}
}
}
register_shutdown_function("byebye");
?>
kalle at meizo dot com
14年前
这可能对那些正在寻找方法获取致命错误回溯的人有所帮助,例如最大内存分配问题,这些问题无法通过用户定义函数处理,从而定位问题

在一个托管许多共享共同 PHP 包含文件的网站的服务器上,我在一个地方设置了

<?php
@ini_set ("error_log", "/my/path/php.err-" . $_SERVER ["HTTP_HOST"] . "-" . $_SERVER ["REMOTE_ADDR"] . "-" . $_SERVER ["REQUEST_METHOD"] . "-" . str_replace ("/", "|", $_SERVER ["REQUEST_URI"]));
?>

实际上我还使用了一些我省略了的软件附加信息,但这样你就能更清晰地找到错误,例如:

/my/path/php.err-website.com-127.0.0.1-GET-path|index.html?xyz

这至少帮助我极大地进一步定位了问题,与之前只是看到内存不足并且不知道是哪个站点/页面不同(因为 PHP 错误只包含它耗尽内存的最新 PHP 代码,通常只是一个共享包含文件,而不是实际页面)。
webmaster at paramiliar dot com
16年前
我们需要使用错误处理程序来处理 SQL 错误,同时传递查询以便记录查询,这是我们想出的方法,它有点像一个丑陋的桥梁,但它能 100% 工作

<?php

function myErrorHandler($errno, $errstr, $errfile, $errline){
switch (
$errno) {
case
E_USER_ERROR:
if (
$errstr == "(SQL)"){
// 处理 sql 错误
echo "<b>SQL Error</b> [$errno] " . SQLMESSAGE . "<br />\n";
echo
"Query : " . SQLQUERY . "<br />\n";
echo
"On line " . SQLERRORLINE . " in file " . SQLERRORFILE . " ";
echo
", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
echo
"Aborting...<br />\n";
} else {
echo
"<b>My ERROR</b> [$errno] $errstr<br />\n";
echo
" Fatal error on line $errline in file $errfile";
echo
", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
echo
"Aborting...<br />\n";
}
exit(
1);
break;

case
E_USER_WARNING:
case
E_USER_NOTICE:
}
/* 不要执行 PHP 内部错误处理程序 */
return true;
}

// 用于测试错误处理的函数

function sqlerrorhandler($ERROR, $QUERY, $PHPFILE, $LINE){
define("SQLQUERY", $QUERY);
define("SQLMESSAGE", $ERROR);
define("SQLERRORLINE", $LINE);
define("SQLERRORFILE", $PHPFILE);
trigger_error("(SQL)", E_USER_ERROR);
}

set_error_handler("myErrorHandler");

// 触发 sql 错误
$query = "SELECT * FROM tbl LIMIT 1";
$sql = @mysql_query($query)
or
sqlerrorhandler("(".mysql_errno().") ".mysql_error(), $query, $_SERVER['PHP_SELF'], __LINE__);


?>
wfinn at riverbed dot com
16年前
"以下错误类型无法通过用户定义函数处理:E_ERROR、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING 以及在调用 set_error_handler() 的文件中引发的大多数 E_STRICT。"

这并不完全正确。set_error_handler() 无法处理它们,但 ob_start() 可以处理至少 E_ERROR。

<?php

function error_handler($output)
{
$error = error_get_last();
$output = "";
foreach (
$error as $info => $string)
$output .= "{$info}: {$string}\n";
return
$output;
}

ob_start('error_handler');

will_this_undefined_function_raise_an_error();

?>
francois vespa
13年前
这是在从终端使用 php(CLI 接口)时的说明。从命令行,即使你有一些错误用户处理程序函数,所以 STDERR 不会显示,致命错误仍然会导致 PHP 解释器显示错误文本。你无法从 php 代码方面解决这个问题。如果使用 UNIX/Linux,你可以在命令末尾添加 " 2>/dev/null" 强制 STDERR 不显示
silkensedai at online dot fr
17年前
我创建了一个错误处理程序,它可以打印回溯并根据某些错误进行终止。如果您希望在发现每个错误时都终止,这将很有用。

<?php

function my_error_handler($errno, $errstr, $errfile, $errline){
$errno = $errno & error_reporting();
if(
$errno == 0) return;
if(!
defined('E_STRICT')) define('E_STRICT', 2048);
if(!
defined('E_RECOVERABLE_ERROR')) define('E_RECOVERABLE_ERROR', 4096);
print
"<pre>\n<b>";
switch(
$errno){
case
E_ERROR: print "错误"; break;
case
E_WARNING: print "警告"; break;
case
E_PARSE: print "解析错误"; break;
case
E_NOTICE: print "提示"; break;
case
E_CORE_ERROR: print "核心错误"; break;
case
E_CORE_WARNING: print "核心警告"; break;
case
E_COMPILE_ERROR: print "编译错误"; break;
case
E_COMPILE_WARNING: print "编译警告"; break;
case
E_USER_ERROR: print "用户错误"; break;
case
E_USER_WARNING: print "用户警告"; break;
case
E_USER_NOTICE: print "用户提示"; break;
case
E_STRICT: print "严格提示"; break;
case
E_RECOVERABLE_ERROR: print "可恢复错误"; break;
default: print
"未知错误 ($errno)"; break;
}
print
":</b> <i>$errstr</i> in <b>$errfile</b> on line <b>$errline</b>\n";
if(
function_exists('debug_backtrace')){
//print "backtrace:\n";
$backtrace = debug_backtrace();
array_shift($backtrace);
foreach(
$backtrace as $i=>$l){
print
"[$i] in function <b>{$l['class']}{$l['type']}{$l['function']}</b>";
if(
$l['file']) print " in <b>{$l['file']}</b>";
if(
$l['line']) print " on line <b>{$l['line']}</b>";
print
"\n";
}
}
print
"\n</pre>";
if(isset(
$GLOBALS['error_fatal'])){
if(
$GLOBALS['error_fatal'] & $errno) die('fatal');
}
}

function
error_fatal($mask = NULL){
if(!
is_null($mask)){
$GLOBALS['error_fatal'] = $mask;
}elseif(!isset(
$GLOBALS['die_on'])){
$GLOBALS['error_fatal'] = 0;
}
return
$GLOBALS['error_fatal'];
}

?>

使用说明

<?php
error_reporting
(E_ALL); // 将报告所有错误
set_error_handler('my_error_handler');
error_fatal(E_ALL^E_NOTICE); // 除E_NOTICE之外,任何错误都将导致终止
?>
dorphalsig at NOSPAMgmail dot com
12 年前
这实际上可以用来捕获致命错误...

<?php
function shutdown()
{
$a=error_get_last();
if(
$a==null)
echo
"没有错误";
else
print_r($a);

}
register_shutdown_function('shutdown');
ini_set('max_execution_time',1 );
sleep(3);
?>

它将输出
Array ( [type] => 1 [message] => Maximum execution time of 1 second exceeded [file] => /path/to/file_name.php [line] => 136 )
Marcelius
15 年前
另一种捕获 PHP 致命错误的方法

<?php
error_reporting
(E_ALL);
ini_set('display_errors', 0);

function
shutdown(){
$isError = false;
if (
$error = error_get_last()){
switch(
$error['type']){
case
E_ERROR:
case
E_CORE_ERROR:
case
E_COMPILE_ERROR:
case
E_USER_ERROR:
$isError = true;
break;
}
}

if (
$isError){
echo
"脚本执行已停止 ({$error['message']})";
} else {
echo
"脚本已完成";
}
}

register_shutdown_function('shutdown');
?>

请注意,这只会捕获运行时错误。因此,在不存在的类中调用方法或两次声明函数不会触发 shutdown 处理程序。
匿名
18 年前
为了尊重 PHP error_reporting() 函数的价值,请使用

<?
if( ($level & error_reporting()) == 0 ) return;
?>
roy
22 年前
需要注意的是,如果您的错误处理程序本身抛出了错误,PHP 非常智能,会使用默认的错误处理程序来处理它。这样,您就不会陷入无限的死亡循环。至少在 PHP 4.2 中,情况确实如此。

(当然,您可以创建自己的处理程序来处理这种情况,但这对于一般目的来说最好保持这种方式。)
jtrick77 at gmail dot com
10 年前
对于任何对实际翻译的错误代码及其含义感兴趣的人

1 E_ERROR (integer) 致命运行时错误。这些错误表示无法恢复的错误,例如内存分配问题。脚本执行将停止。
2 E_WARNING (integer) 运行时警告(非致命错误)。脚本执行不会停止。
4 E_PARSE (integer) 编译时解析错误。解析错误应该只由解析器生成。
8 E_NOTICE (integer) 运行时提示。表明脚本遇到了可能表明错误,但也可能在脚本正常运行过程中发生的事情。
16 E_CORE_ERROR (integer) PHP 初始启动期间发生的致命错误。这就像 E_ERROR,但它是 PHP 核心生成的。
32 E_CORE_WARNING (integer) PHP 初始启动期间发生的警告(非致命错误)。这就像 E_WARNING,但它是 PHP 核心生成的。
64 E_COMPILE_ERROR (integer) 致命编译时错误。这就像 E_ERROR,但它是 Zend 脚本引擎生成的。
128 E_COMPILE_WARNING (integer) 编译时警告(非致命错误)。这就像 E_WARNING,但它是 Zend 脚本引擎生成的。
256 E_USER_ERROR (integer) 用户生成的错误消息。这就像 E_ERROR,但它是使用 PHP 函数 trigger_error() 在 PHP 代码中生成的。
512 E_USER_WARNING (integer) 用户生成的警告消息。这就像 E_WARNING,但它是使用 PHP 函数 trigger_error() 在 PHP 代码中生成的。
1024 E_USER_NOTICE (integer) 用户生成的提示消息。这就像 E_NOTICE,但它是使用 PHP 函数 trigger_error() 在 PHP 代码中生成的。
2048 E_STRICT (integer) 启用此功能以让 PHP 建议对您的代码进行更改,这将确保您的代码具有最佳的互操作性和向前兼容性。自 PHP 5 起可用,但直到 PHP 5.4.0 才包含在 E_ALL 中。
4096 E_RECOVERABLE_ERROR (整数) 可捕获的致命错误。它表示可能发生了危险错误,但没有使引擎处于不稳定状态。如果错误没有被用户定义的处理程序捕获(另见 set_error_handler()),应用程序会像 E_ERROR 一样中止。自 PHP 5.2.0 起
8192 E_DEPRECATED (整数) 运行时通知。启用此选项以接收有关将来版本中不再起作用的代码的警告。自 PHP 5.3.0 起
16384 E_USER_DEPRECATED (整数) 用户生成的警告消息。这类似于 E_DEPRECATED,只是它是使用 PHP 函数 trigger_error() 在 PHP 代码中生成的。自 PHP 5.3.0 起
32767 E_ALL (整数) 所有支持的错误和警告,但 PHP 5.4.0 之前级别 E_STRICT 除外。PHP 5.4.x 中为 32767,PHP 5.3.x 中为 30719,PHP 5.2.x 中为 6143,之前为 2047

(复制自 https://php.net/manual/en/errorfunc.constants.php)
nicolas dot grekas+php at gmail dot com
10 年前
如果您想确保在不重置处理程序堆栈的情况下调用本机 PHP 错误处理程序(因为 set_error_handler(null) 会这样做),您可以简单地调用 set_error_handler,并将 $error_types 设置为零。这在与例如 error_get_last() 结合使用时尤其有用。

<?php

// var_dump 或其他任何东西,因为这永远不会被调用,因为值为 0
set_error_handler('var_dump', 0);
@
$undef_var;
restore_error_handler();

// error_get_last() 现在处于已知状态:
// 未定义变量:undef_var

... // 做一些事情

$e = error_get_last();

...

?>
phpmanual at NO_SPHAMnetebb dot com
20 年前
给定以下代码

class CallbackClass {
function CallbackFunction() {
// 指向 $this
}

function StaticFunction() {
// 不指向 $this
}
}

function NonClassFunction() {
}

似乎有 3 种方法可以在 PHP 中设置回调函数(以 set_error_handler() 为例)

1: set_error_handler('NonClassFunction');

2: set_error_handler(array('CallbackClass', 'StaticFunction'));

3: $o =& new CallbackClass();
set_error_handler(array($o, 'CallbackFunction'));

以下也可能证明有用

class CallbackClass {
function CallbackClass() {
set_error_handler(array(&$this, 'CallbackFunction')); // & 很重要
}

function CallbackFunction() {
// 指向 $this
}
}

文档没有明确概述这三个示例。
phil at propcom dot co dot uk
10 年前
重要的是要注意,如果 E_STRICT 错误触发了错误处理程序,而错误处理程序又尝试使用尚未加载的类,则注册的 SPL 自动加载器将不会被调用。

在这种情况下,您应该手动加载错误处理程序所需的类。
匿名
20 年前
似乎当您让 PHP 知道您有自定义错误处理程序时,您无法在类中更新/设置新变量。示例

<?php
class error {
var
$error;

function
error() {
$this->setIni(); // 这会导致 PHP 忽略对该类的所有其他更改。
}

function
handler() {
echo
$this->error.'!!';
}

function
setText($text) {
$this->error = $text;
}

function
setIni() {
set_error_handler(array($this, 'handler'));
}
}

$eh = new error;
$eh->setText('Error! <br>'); // 这将不会被保存

trigger_error('text', E_USER_ERROR);
// 输出 '!!'
?>

应该怎么做
<?php
class error {
var
$error;

function
error() {
// 暂时不要让 PHP 知道我们的错误处理程序
}

function
handler() {
echo
$this->error.'!!';
}

function
setText($text) {
$this->error = $text;
}

function
setIni() {
set_error_handler(array($this, 'handler'));
}
}

$eh = new error;
$eh->setText('Error! <br>'); // 这将正常工作
$eh->setIni(); // 当您准备好配置类时,调用此方法。所有将要调用的其他方法都不会影响 PHP 的错误处理

trigger_error('text', E_USER_ERROR);
// 输出 'Error! <br>!!'
?>
stepheneliotdewey at GmailDotCom
17年前
手册中指出

"errcontext 将包含一个数组,其中包含错误触发时存在于作用域中的所有变量。用户错误处理程序不得修改错误上下文。"

但是您知道为什么您不能修改错误上下文吗?似乎 errcontext(实际上如果不是字面上的)是通过获取 $GLOBALS 并将非全局局部变量作为该数组中的额外条目添加,然后将整个内容以引用方式传递创建的。

(如果您设置了一个自定义错误处理程序,然后在其中打印 print_r($errcontext),您就可以证明这一点,因为 $GLOBALS 将被打印为递归数组)。

换句话说,手册中的语言具有误导性,因为 errcontext 不是错误触发时存在的变量的副本,而是对调用脚本中*现有活动变量*的引用。

这包括超级全局变量,如 $_SERVER、$_POST、$_GET 等,以及作用域中的所有用户定义的变量。

这意味着,如果您修改 errcontext,您将修改这些其他变量,而不仅仅是在您的错误处理函数的生命周期内,而是在调用脚本的生命周期内。

如果您打算在您的错误处理函数中停止执行,这无关紧要,但是如果您修改了 $errcontext 然后在处理完错误后返回到程序的正常流程,这将导致意外行为,因为变量将保持修改后的状态。例如,如果您在您的自定义错误处理函数中取消设置 $_SERVER,那么一旦函数结束并且您返回到生成错误的页面,它将保持取消设置状态。

这应该在手册中更清楚地说明,首先在上面的“参数”部分中,使用“&”符号将 errhandler 标记为通过引用传递,如下所示

handler ( int $errno, string $errstr [, string $errfile [, int $errline [, array &$errcontext]]] )
Steffen Staehle
19 年前
关于在将应用程序从 php 4.2.1 迁移到 php 4.3.9 时遇到的 set_error_handler() 行为有两个注意事项(我还没有 php 5.0 可用,这可能不适用!)

1. 设置系统错误处理程序

如果您想在设置了自己的错误处理程序后再次设置标准 php 错误处理程序,则可以通过在 php 4.2.1 中传递一个空字符串来实现

<?php

function my_handler($log_level, $log_text, $error_file, $error_line)
{
// 如果这里发生错误,将调用标准错误
//(为了避免递归)

// 做一些有用的事情
// ...
}

$last_handler = set_error_handler("my_handler");

// 此后,$last_handler == ""

// 恢复标准错误处理程序

$last_handler = set_error_handler("");

// 此后,$last_handler == "my_handler"

?>

现在,相同的代码在 php 4.3.9 中会引发错误

set_error_handler() 要求参数 1,“”,是一个有效的回调

(由于对 set_error_handler() 的第一次调用的返回值仍然是空字符串“”,所以我不知道这还能怎么做。我并不真正需要这样做,因为我使用了自己的处理程序,如下所示,但了解这一点可能很好。)

2. 设置您自己的“二级”处理程序

如果您已经设置了自己的错误处理程序,并且想要在执行时用另一个处理程序(除了标准的 php 错误处理程序)替换它,请注意,set_error_handler 在错误处理程序内部使用时的返回值是 "",而不是上一个处理程序的名称!这并不奇怪,因为在您自己定义的错误处理程序执行期间,php 用标准的 php 错误处理程序替换它,以避免在处理程序内部出现问题时出现无限循环。这只有在您想要嵌套的处理程序时才有趣,就像我一样。我的设计背景

一级处理程序:记录到数据库
二级处理程序:记录到平面文件(如果记录到数据库失败)
三级处理程序:打印到标准输出(如果记录到平面文件失败)(最终是系统处理程序)。

<?php

function my_fallback_handler($log_level, $log_text, $error_file, $error_line)
{
// 如果这里发生错误,将调用标准错误
// 以避免递归

// 做一些有用的事
// ...

} // my_fallback_handler

function my_handler($log_level, $log_text, $error_file, $error_line)
{
// 如果这里发生错误,将调用标准错误
// 以避免递归

// 但我们希望有一个与标准错误处理程序不同的回退处理程序

$last_handler = set_error_handler("my_fallback_handler");

// 我期望 $last_handler == "my_handler"
// (它将在 my_handler() 之外)
// 但这里它是一个空字符串 ""

// 做一些有用的事
// ...

// 现在再次设置一级处理程序:
// (不要使用 $last_handler 作为参数,
// 因为它等于 "")

$last_handler = set_error_handler("my_handler");

}
// my_handler

$last_handler = set_error_handler("my_handler");

?>
periklis
14年前
如何在 php 5.2 中处理致命错误

<?php
register_shutdown_function
('shutdownFunction');
function
shutDownFunction() {
$error = error_get_last();
if (
$error['type'] == 1) {
// 做你的事
}
}
?>
a dot ross at amdev dot eu
5 年前
我缺少一种链接错误处理程序的方法。这不是 `set_error_handler` 提供的功能。您必须通过一些操作才能使其正常工作,但它是 *可以* 实现的,通过利用函数的返回值。这是一个示例

<?
$previous = set_error_handler(function ($errno, $errstr, $errfile, $errline, $errcontext) use (&$previous) {
/* 您自定义的错误处理代码在此处。*/

// 如果定义了另一个错误处理程序,则调用它。
if ($previous) {
return $previous($errno, $errstr, $errfile, $errline, $errcontext);
} else {
// 使用标准 PHP 错误处理程序。
return false;
}
});
?>
Klauss
6 年前
大家好。我不知道这是否是先前版本中的旧行为,但目前您可以将异常和错误处理程序设置为私有或受保护的方法,如果,且仅当您在可以访问该方法的上下文中调用 `set_exception_handler()` 或 `set_error_handler()` 时。

示例
<?PHP
$Handler
= new class ()
{
public function
__construct ()
{
set_error_handler([&$this, 'HandleError']);
set_exception_handler([&$this, 'HandleException']);
}
protected function
HandleError ( $Code, $Message, $File = null, $Line = 0, $Context = [] )
{
// 在这里处理错误。
}
private function
HandleException ( $Exception )
{
// 在这里处理异常。
}
}
?>

注意:这些方法必须与回调参数签名匹配。
RGraph
1 年前
一个简单的错误处理程序,使错误更加明显

//
// 将错误处理程序设置为一个打印出更多
// 明显的错误
//
set_error_handler(function ($errno, $errstr)
{
$str = '<div style="margin: 20px; background-color: #fdd; border: 3px solid red; padding: 10px; border-radius: 15px; line-height: 25px"><b>Error: </b>%s (error level: %s)</div>';

printf($str, $errstr, $errno);
});
kaioker
2 年前
超级简单的错误代码到人类可读的转换

function prettycode($code){
return $code == 0 ? "FATAL" : array_search($code, get_defined_constants(true)['Core']);
}
Alex M
3 年前
如果您是编程新手,并且想知道如何将这些错误报告值的组合添加到 .htaccess 文件中。这是一个简短的指南。

使用 PHP 函数 `error_reporting`,我们可以使用按位加运算符 `|` 将选项加在一起。但我们无法在 .htaccess 文件中使用这些常量,而且在我的情况下,我不知道如何添加按位数字。

因此,解决方案可以是将所选选项强制转换为 int

echo (int)(E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR) ;
->263

然后您可以在 .htaccess 中使用 263

php_value error_reporting 263

在我的情况下,我需要将这些错误显示在我的调试服务器上。但组合可能与我的不同。
David Spector
3 年前
PHP 手册没有明确说明如何处理 `@` 运算符错误消息。

这是一个有效的代码

// 如果是 `@` 运算符,则不执行任何操作
$errLevel=error_reporting(E_ALL);
if ($errLevel===0)
return true; // 忽略 `@` 前缀表达式错误
chris at ocproducts dot com
8 年前
请注意,错误处理程序不会递归运行。如果您在错误处理程序运行时出现错误(在错误处理程序本身或从其调用的代码中),则您不会再次调用错误处理程序。

这对 `$php_errormsg` 具有微妙的影响。如果您依赖于错误处理程序来阻止某些类型的错误消息进入 `$php_errormsg`(通过 `return true;`,因为 `error_reporting` 不会影响 `$php_errormsg` 设置),那么这将不适用于在该错误处理程序内调用的任何代码。
mmtache at yahoo dot com
21 年前
`@` 运算符将 `error_reporting()` 值设置为 0。
这意味着您也可以在自己的错误处理程序中使用它。例如

function userErrorHandler($errno, $errmsg, $filename, $linenum, $vars) {
if (error_reporting())
echo $errmsg;
}
set_error_handler("userErrorHandler");

function test(){
trigger_error("Error Message", E_USER_WARNING);
}

@test(); // 不输出任何内容
ash
17年前
错误处理函数,同时处理错误和异常;还具有包含可能函数参数的回溯。

<?php

$cfg
= array();
$cfg['debug'] = 1;
$cfg['adminEmail'] = '[email protected]';

function
errorHandler($errno, $errstr='', $errfile='', $errline='')
{
// 如果错误被 @ 抑制
if (error_reporting() == 0) {
return;
}

global
$cfg;

// 检查函数是否被异常调用
if(func_num_args() == 5) {
// 由 trigger_error() 调用
$exception = null;
list(
$errno, $errstr, $errfile, $errline) = func_get_args();

$backtrace = array_reverse(debug_backtrace());

}else {
// 捕获异常
$exc = func_get_arg(0);
$errno = $exc->getCode();
$errstr = $exc->getMessage();
$errfile = $exc->getFile();
$errline = $exc->getLine();

$backtrace = $exc->getTrace();
}

$errorType = array (
E_ERROR => 'ERROR',
E_WARNING => 'WARNING',
E_PARSE => 'PARSING ERROR',
E_NOTICE => 'NOTICE',
E_CORE_ERROR => 'CORE ERROR',
E_CORE_WARNING => 'CORE WARNING',
E_COMPILE_ERROR => 'COMPILE ERROR',
E_COMPILE_WARNING => 'COMPILE WARNING',
E_USER_ERROR => 'USER ERROR',
E_USER_WARNING => 'USER WARNING',
E_USER_NOTICE => 'USER NOTICE',
E_STRICT => 'STRICT NOTICE',
E_RECOVERABLE_ERROR => 'RECOVERABLE ERROR'
);

// 创建错误信息
if (array_key_exists($errno, $errorType)) {
$err = $errorType[$errno];
} else {
$err = 'CAUGHT EXCEPTION';
}

$errMsg = "$err: $errstr in $errfile on line $errline";

// 开始回溯
foreach ($backtrace as $v) {

if (isset(
$v['class'])) {

$trace = 'in class '.$v['class'].'::'.$v['function'].'(';

if (isset(
$v['args'])) {
$separator = '';

foreach(
$v['args'] as $arg ) {
$trace .= "$separator".getArgument($arg);
$separator = ', ';
}
}
$trace .= ')';
}

elseif (isset(
$v['function']) && empty($trace)) {
$trace = 'in function '.$v['function'].'(';
if (!empty(
$v['args'])) {

$separator = '';

foreach(
$v['args'] as $arg ) {
$trace .= "$separator".getArgument($arg);
$separator = ', ';
}
}
$trace .= ')';
}
}

// 显示错误信息,如果调试已启用
if($cfg['debug'] == 1) {
echo
'<h2>Debug Msg</h2>'.nl2br($errMsg).'<br />
Trace: '
.nl2br($trace).'<br />';
}

// 该做什么
switch ($errno) {
case
E_NOTICE:
case
E_USER_NOTICE:
return;
break;

default:
if(
$cfg['debug'] == 0){
// 发送邮件给管理员
if(!empty($cfg['adminEmail'])) {
@
mail($cfg['adminEmail'],'critical error on '.$_SERVER['HTTP_HOST'], $errorText,
'From: Error Handler');
}
// 结束并显示错误信息
exit(displayClientMessage());
}
else
exit(
'<p>aborting.</p>');
break;

}

}
// errorHandler() 结束

function displayClientMessage()
{
echo
'some html page with error message';

}

function
getArgument($arg)
{
switch (
strtolower(gettype($arg))) {

case
'string':
return(
'"'.str_replace( array("\n"), array(''), $arg ).'"' );

case
'boolean':
return (bool)
$arg;

case
'object':
return
'object('.get_class($arg).')';

case
'array':
$ret = 'array(';
$separtor = '';

foreach (
$arg as $k => $v) {
$ret .= $separtor.getArgument($k).' => '.getArgument($v);
$separtor = ', ';
}
$ret .= ')';

return
$ret;

case
'resource':
return
'resource('.get_resource_type($arg).')';

default:
return
var_export($arg, true);
}
}

?>
devermin at ti0n dot net
14年前
在工作中,我有一些代码存在未捕获的错误,导致了数据完整性的丢失(例如,使用 file_get_contents 调用 Web 服务时,代码会静默失败,之后在数据库中插入垃圾数据)。

我找到了一种解决方案,可以将特定类型的错误转换为异常,然后根据错误类别选择性地采取行动。

<?php
ini_set
('error_reporting',E_ALL^E_NOTICE);

## 保留前 10 位用于初始错误号
define('EMASK',(~0)<<10);
define('ECODEMASK',~EMASK);
## 类别
define('IOERROR', 1<<10);
define('EMPTYPARMS', 1<<11);
define('FAILURE', 1<<12);
## 字符串错误模式 => 代码

$catch_me=array(
"/^(file_get_contents)\((.*)\).*failed to open stream: (.*)/ " =>
array (
'mesg' => "IO::无法打开流",
'code' => IOERROR | FAILURE
),
"/^fopen\(.*\): Filename cannot be empty/" =>
array(
'msg' => "参数::空",
'code' => EMPTYPARMS
)
);
function
error_2_exception($errno, $errstr, $errfile, $errline,$context) {
global
$catch_me;
foreach (
$catch_me as $regexp => $res) {
if(
preg_match($regexp,$errstr,$match)){
throw new
Exception($res['mesg'],$res['code']|( $errno & EMASK ) );
}
}
/* 切换回 PHP 内部错误处理程序 */
return false;
}
## => 想要捕获这个错误
$f=file_get_contents("mlsdkfm");
## 不想破坏现有的错误行为(所以没有被捕获)
$f=file_get_contents('');
## 魔法
set_error_handler("error_2_exception");
## 行为保持不变
$f=file_get_contents('');
try {
## 现在无法正常工作的 Web 服务会抛出异常 \o/
$f=file_get_contents("mlsdkfm");
} catch(
Exception $e) {
## 我可以按类别对异常进行分组
echo ( $e->getCode() & FAILURE ) ? "\nEPIC FAIL\n" : "\nbegnine";
}

?>
To Top