致命错误:PHP

10

在PHP中,当出现致命错误时,有没有一种方法使代码继续执行而不是退出呢?例如,我遇到了超时致命错误,我希望无论何时出现此类错误都可以跳过此任务并继续执行其他任务。但是,在这种情况下脚本会退出。


如果你运行的 PHP 脚本需要超过 2-4 秒才能执行完毕,那么你肯定做错了什么重要的事情。使用另一种技术或改变你的工作流程吧。 - Alec Smart
3
我不同意这个观点- cron job等通常需要超过几秒钟的时间。也许用C++可以运行得更快,但是那就需要雇佣一位C++程序员... - Greg
6个回答

14

使用输出缓冲的方法可以记录某些致命错误,但在发生致命错误后无法继续执行脚本 - 这就是它被称为致命的原因!

如果您的脚本因超时而停止,请使用set_time_limit()函数来为其提供更多执行时间。


7
"Fatal Error",顾名思义,是致命的:它会停止脚本/程序的执行。
如果您正在使用PHP生成网页,并且出现与max_execution_time相关的致命错误,默认情况下为30秒,那么您肯定正在做一些需要很长时间的事情:用户可能不会等待那么长时间来获取页面。
如果您正在使用PHP进行一些重量级计算,而不是在网页上(而是通过CLI、cron或类似工具),则可以为max_execution_time设置另一个(更大的)值。有两种方法可以做到这一点:
第一种方法是修改php.ini以设置此值(该值已经在文件中;只需编辑属性的值)。问题是它也会修改Web服务器的值,这是不好的(毕竟这是一项安全措施)。 更好的方法是创建一个名为phpcli.ini的php.ini副本,并修改此文件。然后,在调用php时使用它:
php -c phpcli.ini myscript.php

如果您需要为CLI执行配置许多属性(例如memory_limit,通常需要设置为较高的值以运行长时间批处理),则这将非常有效。另一种方法是在调用php时定义不同的max_execution_time值,如下所示:
php -d max_execution_time=60 myscript.php

这很棒,如果你例如通过crontab启动它。

1
如果您有合适的PHP版本(PHP>=5.2 for error_get_last),您可以尝试在这里描述的技术here,该技术使用register_shutdown_function和error_get_last。
这不允许您在发生致命错误时“继续”,但它至少允许您在向用户显示自定义错误页面之前记录错误(并可能发送警告电子邮件)。
它的工作原理类似于以下内容:
function fatalErrorHandler()
{
    $lastError = error_get_last();
    if (isset($lastError["type"]) && $lastError["type"]==E_ERROR) {
      // do something with the fatal error
    }
}
...
register_shutdown_function('fatalErrorHandler');


几点需要注意:

  • 您可以使用ob_clean()函数来删除在致命错误之前生成的任何内容。
  • 在关闭处理程序中执行任何过于繁重的操作都是一个非常糟糕的想法,这种技术是关于优雅失败而不是恢复。
  • 无论您做什么,都不要尝试将错误记录到数据库中...如果是数据库超时导致致命错误怎么办?
  • 由于某些原因,在Windows上使用WAMP进行开发时,我曾经遇到过无法100%地使此技术正常工作的问题。

1

我能给你的最简单的答案就是这个函数:http://php.net/manual/en/function.pcntl-fork.php

更详细地说,你可以做到以下几点:

  • 复制你认为可能会导致致命错误(即你的大量代码)的进程部分
  • 复制该进程的脚本应该非常简单。

例如,这是我在作业队列中会做的事情之一:

<?php
// ... load stuff regarding the job queue

while ($job = $queue->getJob()) {
    $pid = pcntl_fork();
    switch ($pid) {
        case -1:
            echo "Fork failed";
            break;
        case 0:
            // do your stuff here
            echo "Child finished working";
            break;
        default:
            echo "Waiting for child...";
            pcntl_wait($status);
            // check the status using other pcntl* functions if you want
            break;
    }
}

1

这取决于具体的错误类型。您可以通过创建自己的错误处理程序来捕获错误。请参阅set_error_handler()上的文档,但并非所有类型的错误都可以被捕获。查看您收到的超时错误并查看其类型。如果它是E_ERROR、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR或E_COMPILE_WARNING之一,则无法使用错误处理程序捕获它。如果是其他类型,则可以使用错误处理程序捕获它并简单地返回。


0
有没有一种方法可以限制函数的执行时间,而不是整个脚本? 例如:
function blabla()
{
return "yes";
}

要使其在25秒内未执行则返回无。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接