致命错误php

时间:2009-07-17 08:49:44

标签: php error-handling

当你在PHP中遇到致命错误时,有没有办法让代码继续(不退出)? 例如,我得到一个超时致命错误,我希望每当它碰巧跳过此任务并继续与其他人。 在这种情况下,脚本退出。

6 个答案:

答案 0 :(得分:14)

有一个使用输出缓冲的黑客可以让你记录某些致命错误,但是在发生致命错误后无法继续编写脚本 - 这就是致命的原因!

如果您的脚本超时,您可以使用set_time_limit()为其提供更多时间来执行。

答案 1 :(得分:7)

“致命错误”,正如其名称所示,是致命的:它会停止执行脚本/程序。

如果您使用PHP生成网页并获得与max_execution_time相关的致命错误,默认情况下,等于30秒,您肯定会做一些真正花费太多时间的事情:用户可能不会等待这么长时间才能获得该页面。

如果您使用PHP进行一些繁重的计算,而不是在网页(但通过CLI,或cron,或类似的东西),您可以设置另一个(更大) max_execution_time值。 你有两种方法:

首先是修改php.ini,设置这个值(它已经在文件中;只需编辑属性的值)。问题是它还会为Web服务器修改它,这是不好的(毕竟这是一个安全措施)。 更好的方法是创建一个php.ini的副本,例如,phpcli.ini,并修改此文件。然后,在调用php时使用它:

php -c phpcli.ini myscript.php

如果您需要为CLI执行配置许多属性,这将非常有用。 (与memory_limit类似,通常必须为长期运行的批次设置更高的值

另一种方法是在调用php时为max_execution_time定义一个不同的值,如下所示:

php -d max_execution_time=60 myscript.php

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

答案 2 :(得分:1)

这取决于确切的错误类型。您可以通过创建自己的错误处理程序来捕获错误。请参阅set_error_handler()上的文档,但不能捕获所有类型的错误。查看您获得的超时错误,看看它是什么类型。如果它是E_ERROR,E_PARSE,E_CORE_ERROR,E_CORE_WARNING,E_COMPILE_ERROR或E_COMPILE_WARNING之一,那么您无法通过错误处理程序捕获它。如果它是另一种类型,那么你可以。使用错误处理程序捕获它,然后返回。

答案 3 :(得分:1)

如果您有合适的PHP版本(对于error_get_last,PHP> = 5.2),您可以尝试使用register {shutdown_function和error_get_last的here描述的技术。

当您收到致命错误时,这将不允许您“继续”,但它至少允许您在向用户显示自定义错误页面之前记录错误(并可能发送警告电子邮件)。

它的工作原理如下:

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()删除致命错误之前生成的任何内容。
  • 在关机处理程序中做任何事情都是真的坏主意,这种技术是关于优雅的失败而不是恢复。
  • 无论你做什么,都不要尝试将错误记录到数据库中...如果是导致致命错误的数据库超时怎么办?
  • 由于某些原因,我在使用WAMP在Windows中进行开发时,有100%的时间使用此技术时遇到了问题。

答案 4 :(得分:0)

有没有办法限制函数的执行时间而不是所有脚本? 例如

function blabla()
{
return "yes";
}

使它如果在25秒内没有执行则返回no;

答案 5 :(得分:0)

我能给你的最简单的答案就是这个功能: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;
    }
}