是否可以在全局范围内让 PHP 在收到通知/警告时停止执行?
我们运行一个有很多站点的开发服务器,但希望迫使我们的开发人员修复这些警告/通知(或至少寻求帮助)而不是忽略并继续前进。
是否可以在全局范围内让 PHP 在收到通知/警告时停止执行?
我们运行一个有很多站点的开发服务器,但希望迫使我们的开发人员修复这些警告/通知(或至少寻求帮助)而不是忽略并继续前进。
是的,有可能。这个问题涉及如何处理 PHP 中的错误的更普遍的问题。set_error_handler
您应该使用文档定义和注册自定义错误处理程序,以自定义 PHP 错误处理。
恕我直言,最好对任何 PHP 错误抛出异常并使用 try/catch 块来控制程序流,但在这一点上意见不同。
为了实现 OP 的既定目标,您可能会执行以下操作:
function errHandle($errNo, $errStr, $errFile, $errLine) {
$msg = "$errStr in $errFile on line $errLine";
if ($errNo == E_NOTICE || $errNo == E_WARNING) {
throw new ErrorException($msg, $errNo);
} else {
echo $msg;
}
}
set_error_handler('errHandle');
上面的代码将在ErrorException
任何时候抛出E_NOTICE
or E_WARNING
,有效地终止脚本输出(如果没有捕获到异常)。对 PHP 错误抛出异常最好与并行异常处理策略 ( set_exception_handler
) 结合使用,以便在生产环境中优雅地终止。
请注意,上面的示例将不考虑@
错误抑制运算符。如果这对您很重要,只需使用error_reporting()
此处演示的函数添加一个检查:
function errHandle($errNo, $errStr, $errFile, $errLine) {
if (error_reporting() == 0) {
// @ suppression used, don't worry about it
return;
}
// handle error here
}
可以通过使用auto_prepend_file
指令Docs 指定所有 PHP 进程包含的文件来完成:
auto_prepend_file "/full/path/to/a/prepend-file.php"
在全局 php.ini 文件中执行此操作将确保始终执行前置文件中的代码。然后使用它来注册一个全局错误处理程序,它将所有错误转换为异常文档:
<?php
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler("exception_error_handler");
这个小脚本会将所有错误/警告/通知等转换为ErrorException
.
此代码示例可能太短(将在下面进一步评论),因此请不要错过set_error_handler()
Docs手册页上的示例。
将它与error_reporting
ini 指令Docs 结合使用,这些值在您的 php.ini 文件中进行了描述(或者作为另一个选项,使用第二个参数按其严重性set_error_handler
处理错误)。
抛出异常是一件非常严格的事情。您的程序员将被迫处理警告和错误,否则代码将无法工作(包括带有@
错误控制运算符的代码,使其无效)。
可能这太过分了,在公司内部不被社会接受。相反,您还可以通过使用输出缓冲记录所有错误并将它们添加到输出的末尾(或在顶部以便更明显)。
创建(但不抛出)错误异常已经捕获了一个可用于错误处理的回溯。
显示错误和警告的另一种方法是将它们记录到日志文件中,然后使用另一个进程监视该文件并汇总信息。您可以创建一个记分牌来显示每个应用程序的警告数量,并将其显示在办公室中,这样每个人都可以看到团队的表现或类似的乐趣。
我想说的是:除了技术问题之外,这是一个社会问题,你需要创造性地解决这个问题,并实际与你的开发人员讨论这个问题。您需要明确为什么修复警告和错误很重要,以及他们的编码和技能将如何从中受益。
自 PHP 5.3.0 起:
set_error_handler(
function(int $nSeverity, string $strMessage, string $strFilePath, int $nLineNumber){
if(error_reporting()!==0) // Not error suppression operator @
throw new \ErrorException($strMessage, /*nExceptionCode*/ 0, $nSeverity, $strFilePath, $nLineNumber);
},
/*E_ALL*/ -1
);
如果您在开发环境中,您可能会考虑安装模块 Xdebug 并xdebug.halt_level=E_WARNING|E_NOTICE|E_USER_WARNING|E_USER_NOTICE
在 PHP ini 文件中的某个位置进行设置。开发人员可以 reset xdebug.halt_level
,但我们对基于 的答案有同样的问题set_error_handler
,因为我们可以将处理程序恢复到其原始值。
其他解决方案实现了一个自定义错误处理程序,它覆盖了默认的错误记录机制。这意味着当我们设置自定义错误处理程序时,通知/警告不再以默认方式打印,因此我们更改的不仅仅是“在通知/警告时停止脚本执行”。
但是,我需要一种仍然打印消息的方法——在我的情况下是在 PHP CLI 中——因为输出随后会被另一个程序解析。所以我不想以某种方式打印消息,但与 PHP 通常使用的方式完全相同。我只是想在打印通知/警告后立即使用退出代码停止PHP CLI 进程,并且不要更改任何其他内容。!= 0
不幸的是,似乎没有在不更改整个错误处理的情况下退出脚本的默认方式。所以我需要在 PHP 中重新实现默认的错误处理程序(用 C 实现)。
为此,我查看了 PHP 源代码中的默认错误打印机制,并将相关部分从 C 移植到 PHP,以获得以下错误处理程序,我想与您分享,以防您需要类似的东西:
set_error_handler(
function($errNo, $errStr, $errFile, $errLine) {
$error_type_str = 'Error';
// Source of the switch logic: default error handler in PHP's main.c
switch ($errNo) {
case E_ERROR:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_USER_ERROR:
$error_type_str = "Fatal error";
break;
case E_RECOVERABLE_ERROR:
$error_type_str = "Recoverable fatal error";
break;
case E_WARNING:
case E_CORE_WARNING:
case E_COMPILE_WARNING:
case E_USER_WARNING:
$error_type_str = "Warning";
break;
case E_PARSE:
$error_type_str = "Parse error";
break;
case E_NOTICE:
case E_USER_NOTICE:
$error_type_str = "Notice";
break;
case E_STRICT:
$error_type_str = "Strict Standards";
break;
case E_DEPRECATED:
case E_USER_DEPRECATED:
$error_type_str = "Deprecated";
break;
default:
$error_type_str = "Unknown error";
break;
}
fwrite(STDERR, "PHP $error_type_str: $errStr in $errFile on line $errLine\n");
exit(1);
},
E_ALL
);
您可以在服务器的 PHP 配置文件中打开error_reporting to E_ALL。
在 PHP 5 中提供了一个新的错误级别 E_STRICT。由于 E_STRICT 不包含在 E_ALL 中,因此您必须明确启用这种错误级别。在开发过程中启用 E_STRICT 有一些好处。STRICT 消息将帮助您使用最新最好的建议编码方法,例如警告您不要使用已弃用的函数。
参考:PHP 配置手册
以下设置指导您输出脚本中的所有错误。请注意,这些将需要包含在所有脚本文件的开头。
<?php
// Turn off all error reporting
error_reporting(0);
// Report simple running errors
error_reporting(E_ERROR | E_WARNING | E_PARSE);
// Reporting E_NOTICE can be good too (to report uninitialized
// variables or catch variable name misspellings ...)
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);
// Report all errors except E_NOTICE
// This is the default value set in php.ini
error_reporting(E_ALL ^ E_NOTICE);
// Report all PHP errors (see changelog)
error_reporting(E_ALL);
// Report all PHP errors
error_reporting(-1);
// Same as error_reporting(E_ALL);
ini_set('error_reporting', E_ALL);
?>