【问题标题】:Catch ErrorException that wraps a fatal PHP error捕获包含致命 PHP 错误的 ErrorException
【发布时间】:2013-11-29 22:28:23
【问题描述】:

在我自制的 PHP MVC 框架中,我编写了一个小错误处理程序,它将 PHP 错误包装在异常中,然后将其抛出。

class ErrorController extends ControllerAbstract {

    ...

    public static function createErrorException($number, $message = NULL, $file = NULL, $line = NULL, array $context = array()) {
        throw new ErrorException($message, $number, 0, $file, $line);
    }
}

然后使用set_error_handler() 注册。这工作正常,除了致命错误(没有双关语)。我的自定义错误处理程序仍然被调用,但我无法捕捉到抛出的 ErrorException

这种错误的一个例子是试图包含一个不存在的文件:

    try {
        require 'Controller/NonExistentController.php';
    } catch (ErrorException $exc) {
        echo $exc->getTraceAsString(); // code never reaches this block
    }

我的自定义错误处理程序被调用并引发异常,但代码从未到达“catch”块。相反,PHP 生成 HTML(糟糕!):


警告:未捕获的异常“ErrorException”与 消息 'require(Controller/NonExistentController.php): 无法打开流:...

接着是:

致命错误:Program::main():需要打开失败 'Controller/NonExistentController.php' (include_path='.:') in ...

我不想尝试从致命错误中恢复,但我确实希望我的代码能够正常退出。在这种情况下,这意味着发回指示内部错误的 XML 或 JSON 响应,因为这是一个 REST 应用程序,而这正是我的客户所期望的。 HTML 响应也很可能会破坏客户端应用程序。

我应该采取不同的方式吗?

【问题讨论】:

  • 哈哈,PHP错误处理,总是让我傻笑,“@,关于文件不存在的警告不会被打印出来。但是如果在php中设置了scream.enabled,它就会被打印出来。 “是的....
  • 哦,我最喜欢的“可捕获的致命错误”
  • 我承认我被 C# 中异常处理的简单程度所宠坏了,但在 PHP 中肯定不会那么困难吗?
  • PHP 有很多问题,== 运算符是错误的,strpos 返回 0,这可能是假的...阅读me.veekun.com/blog/2012/04/09/php-a-fractal-of-bad-design 老实说,我认为这无法解决, A for努力,但是....值得一试吗?
  • 我只是不喜欢 PHP 随时生成 HTML 输出。不过,我还没有研究如何配置 php.ini 文件。我以为世界已经从ini文件开始了。

标签: php error-handling fatal-error


【解决方案1】:

在 php.net 上查看有关 require 的文档:

requireinclude 相同,但失败时也会产生致命的 E_COMPILE_ERROR 级别错误。换句话说,它 将停止脚本,而 include 仅发出警告 (E_WARNING) 这允许脚本继续。

在您的情况下,您可以借助 register_shutdown_function 处理致命错误,这需要 PHP 5.2+:

function customFatalHandler() {
  $error = error_get_last();

  if( $error === NULL) {
      return;
  }

  $type   = $error["type"];
  $file = $error["file"];
  $line = $error["line"];
  $message  = $error["message"];

  echo "Error `$type` in file `$file` on line $line with message `$message`"; 
}

register_shutdown_function("customFatalHandler");

这对你也有帮助

  1. error_get_last() and custom error handler
  2. Why doesn't PHP catch a "Class not found" error?

【讨论】:

  • 我什至不明白requireinclude 之间的区别,直到它扇了我一耳光。感谢您清除它!
  • 我设法让您的解决方案正常工作,但它不会抑制 HTML 警告。那是怎么回事?
  • 你是对的。使用 @ 运算符为 require 语句添加前缀也有效。我仍然想知道我应该怎么知道这一切。
  • 啊!这让我很受挫。似乎 1 行代码可以生成多个错误(例如 1x E_WARNING 和 1x E_ERROR),具体取决于错误报告设置。你觉得这对吗?
【解决方案2】:

很抱歉得到这样否定的答案,但你(很可能)不能。

PHP 的设计目的是为了某种奇怪的原因尽可能长时间地运行,你有错字吗?默默地将该变量初始化为null,你把[]放在某事之后,如果运算符没有意义,则评估为null!

这对于错误处理来说更加混乱,有 4 个系统无法协同工作。 PHP 通过“猴子补丁”进行一些错误处理,如果您尝试通过抛出来处理错误处理程序中的某些内容,这会导致问题,在处理程序退出之前它不会“未修补”。

使用关闭处理程序,从那里抛出可能会导致巨大的问题!之前被它咬过,我不想谈了:P

它还定义了 PHP 中的文件“资源”是否在关闭时关闭,它的创建是为了帮助插件在网络服务器上进行整理。 (因此您可以列出它们)

【讨论】:

  • 就在我以为我开始掌握它的时候。非常令人沮丧。 :(
  • @StevenLiekens 我讨厌 Php,我讨厌“数组”既不是列表也不是关联容器,我讨厌错误处理,我讨厌在更大的图景中无法真正发挥作用的固定功能。 PHP 是一种特殊的语言,因为它永远不会自然而然地出现,你总是需要搜索,是 str2upper 还是 str_to_upper 不!这是strtoupper 等待str_replace wtf?如果您可以使用 Python,请使用 Python。它是一种有意义的语言,它是一致且经过深思熟虑的,并且比 PHP 容易得多。
  • 嗯,我正在交叉编译,所以我可能会花更多的时间让 Python 工作,而不是解决 PHP 的愚蠢问题。不过我会考虑的。
  • 交叉编译....php?不管 Python 更容易上手,更容易扩展……它真的值得一看。
  • 我指的是真正的 PHP 解释器,而不是我的脚本。我正在为不同的 CPU 架构(确切地说是 MIPS)进行编译,其中不存在预编译的二进制文件。我让 PHP 工作,但 Python 可能完全不同。
猜你喜欢
  • 2011-01-20
  • 1970-01-01
  • 1970-01-01
  • 2019-04-20
  • 2022-12-10
  • 2021-12-13
  • 2014-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多