在发出通知/警告时停止脚本执行

Mic*_*ael 38 php configuration

是否可以让PHP在全局通知/警告后停止执行?

我们运行一个开发服务器上有很多站点,但是想强迫我们的开发人员修复这些警告/通知(或者至少向他们寻求帮助)而不是忽略并继续前进.

rdl*_*rey 52

对的,这是可能的.这个问题涉及如何处理PHP中的错误这一更普遍的问题.您应该使用set_error_handlerdocs定义和注册自定义错误处理程序,以自定义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');
Run Code Online (Sandbox Code Playgroud)

上面的代码将ErrorException随时抛出E_NOTICEE_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
}
Run Code Online (Sandbox Code Playgroud)

  • @BryanH我是一个很大的支持者,你的代码应该完全封装正在发生的事情.`auto_prepend_file`太过于"神奇",而且从查看你的代码到底发生了什么变得不清楚.说别人必须维护你的代码.他们怎么知道你在php.ini中埋了一些"自动包含"?如果该自动前置文件有错误怎么办?谈论**调试理智的噩梦**.没有充分的理由不在代码中直接使用`require`."auto_prepend_file"是一个*可怕的想法恕我直言. (5认同)

hak*_*kre 6

您可以在全球范围内的配置此php.ini文件文档.

您通过指定被包括通过与所有PHP进程的一个文件auto_prepend_file指令文件:

auto_prepend_file "/full/path/to/a/prepend-file.php"
Run Code Online (Sandbox Code Playgroud)

在你的全局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");
Run Code Online (Sandbox Code Playgroud)

这个小脚本会将所有错误/警告/通知等变为ErrorException.

将它与error_reportingini指令Docs结合使用,这些值在php.ini文件中描述.

抛出异常是非常严格的事情.您的程序员将被迫处理警告和错误,否则代码将无法正常工作.

可能这对您的程序员来说太过分了,而且在公司内部并不是社会可接受的.相反,您还可以通过使用输出缓冲来记录所有错误并将其添加到输出的末尾(或者在顶部,以便更加明显).

另一种方法是将错误和警告记录到日志文件中,然后使用另一个进程监视该文件并聚合信息.您可以创建一个记分板,显示每个应用程序的警告数量,并使其在办公室中可见,这样每个人都可以看到团队的表现如何,或者像这样有趣.

我想说的是:除了技术问题之外,这是一个社交问题,你需要具有创造性,并实际上从你的开发人员那里解决问题.您需要弄清楚为什么修复警告和错误以及他们的编码和技能将如何从中受益非常重要.

  • 根据记录,我不支持使用“auto_prepend_file”。我认为代码应该明确说明正在发生的事情。我不希望 php.ini 指令导致我在实际源代码中看不到的神奇行为。恕我直言,进行简单的“require”调用会更好。一个月后,当您查看一段代码并失去理智,因为无法理解为什么会发生某些事情时,会发生什么?如果新开发人员加入团队会发生什么?他们不知道 php.ini 指令会自动包含代码。 (2认同)

Tib*_*tan 6

从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
);
Run Code Online (Sandbox Code Playgroud)


小智 5

如果您在开发环境中,您可能会考虑安装模块 Xdebug 并设置xdebug.halt_level=E_WARNING|E_NOTICE|E_USER_WARNING|E_USER_NOTICE在您的 PHP ini 文件中的某个位置。开发人员可以重置xdebug.halt_level,但我们对基于 的答案有同样的问题set_error_handler,因为我们可以将处理程序恢复到其原始值。


lee*_*mes 5

其他解决方案实现了一个自定义错误处理程序,它覆盖了默认的错误日志记录机制。这意味着当我们设置自定义错误处理程序时,不再以默认方式打印通知/警告,因此我们更改的不仅仅是“在通知/警告时停止脚本执行”。

但是,我需要一种方法来仍然打印消息(在我的例子中是在 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
);
Run Code Online (Sandbox Code Playgroud)