获取子进程的“PHP Fatal Error”的输出
我已经了解到,您无法捕获 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可以在子进程中注册一个关闭函数并检查调用时最后一个错误。如果存在与致命类型之一匹配的错误(
E_ERROR
、E_COMPILE_ERROR
、E_CORE_ERROR
和E_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
, andE_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.我找不到任何可以让您使用类似于您正在使用的方法来重定向 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.