获取子进程的“PHP Fatal Error”的输出

发布于 2024-10-26 14:32:18 字数 819 浏览 1 评论 0原文

我已经了解到,您无法捕获 PHP 致命错误,并且您的脚本将在遇到错误时立即终止。我正在 CI 服务器上运行一个大型 PHP 测试套件(不是 PHPUnit,而是一个自定义解决方案),并且希望以 JUnit 输出格式报告测试通过/失败。

由于 PHP 中太多的事情都是“致命错误”,我不希望致命错误结束我的测试运行,所以我的解决方案是使用分叉,如下所示:

foreach($tests as $test) {
    $pid = pcntl_fork();
    if ($pid) {
        $test->run();
        $test->write_junit($some_file_name);
    }
    else {
        pcntl_wait($status);
        if ($status) { //fatal error
            // from here we have no data about why it 
            // crashed, since that was in the child's memory
        }
    }
}

我的想法是关闭子进程中的 STDERR 并让它将标准错误发送到父级可以读取的管道并将错误数据保存到 JUnit 文件中,但现在我不知道这是否可能。您可以更改 STDERR 文件吗?基本上,我想做的就像 popen 但没有 exec( ) 步。

在子进程因 PHP 致命错误而死亡后,我可以获得其输出吗?

I've already learned that you can't catch PHP Fatal Errors, and your script will terminate about as soon as it hits one. I'm running a large PHP test suite (not PHPUnit, but a custom solution) on a CI server, and want to have the test pass/failures to be reported in JUnit output format.

Since way too many things in PHP are "Fatal Errors", I don't want the Fatal Error to end my test run, so my solution was to use forking, something like this:

foreach($tests as $test) {
    $pid = pcntl_fork();
    if ($pid) {
        $test->run();
        $test->write_junit($some_file_name);
    }
    else {
        pcntl_wait($status);
        if ($status) { //fatal error
            // from here we have no data about why it 
            // crashed, since that was in the child's memory
        }
    }
}

My idea was to close the STDERR in the child and have it send it's standard error to a pipe that the parent can read and save the error data into the JUnit file, but now I don't know if that's possible. Can you change the file for STDERR? Basically, what I want to do is like popen but without the exec() step.

Can I get the output of a child process after it died of a PHP Fatal Error?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

装迷糊 2024-11-02 14:32:18

您可以在子进程中注册一个关闭函数并检查调用时最后一个错误。如果存在与致命类型之一匹配的错误(E_ERRORE_COMPILE_ERRORE_CORE_ERRORE_PARSE),将其写入 JUnit 文件中。虽然您无法从致命错误中恢复,但您的关闭函数仍会被调用。

更新:正如Pacerier在评论中指出的那样,由于E_CORE_ERROR仅在PHP解释器引导自身时抛出,因此它发生在关闭函数可以注册之前并且无法被捕获。

You can register a shutdown function in the child process and check the last error when it's called. If there's an error that matches one of the fatal types (E_ERROR, E_COMPILE_ERROR, E_CORE_ERROR, and E_PARSE), write it into the JUnit file. While you cannot recover from a fatal error, your shutdown function is still called.

Update: As Pacerier points out in the comments, since E_CORE_ERROR is only thrown while the PHP interpreter is bootstrapping itself, it occurs before a shutdown function can be registered and cannot be trapped.

找回味觉 2024-11-02 14:32:18

我找不到任何可以让您使用类似于您正在使用的方法来重定向 stderr 的东西。

但是,您也许可以在您的孩子中使用 ini_set('error_log', $some_log_path) ,然后在孩子崩溃时读取该文件以确定错误消息?

如果做不到这一点,您可以重写代码以通过 proc_open 调用单独的单测试运行程序 PHP 包装器,并使用 shell 将 stderr 发送到正常的地方。

I wasn't able to find anything that would allow you to redirect stderr with an approach like the one you are using.

However, you could perhaps use ini_set('error_log', $some_log_path) in your child and then read the file if the child crashed to determine the error message?

Failing that, you could rewrite your code to invoke a separate single-test-runner PHP wrapper via proc_open and use the shell to send stderr to somewhere sane.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文