14

当我运行“Behat”步骤时,Behat 错误处理程序会将“尝试获取非对象的属性”错误转换为异常。

这非常有用,因为它会导致步骤被标记为失败,并允许测试运行在下一个场景中继续。

但是,“调用非对象上的成员函数”错误是致命的,并立即停止测试执行(包括中止将结果写入 xml)。这是无益的。

我的问题是:

  1. 这两个错误有什么区别?它们是不同的“错误级别”吗?这是在哪里记录的?我搜索了 PHP 站点和谷歌,找不到规范的参考,只有很多关于调试每个错误的特定实例的问题。

  2. 有没有办法将后一个错误转换为异常,而不是完全停止脚本?在我看来,null用“ ”取消引用“ ->”不会是“无法恢复的错误,例如内存分配问题”。

更新:

看起来这只是 PHP 的一个已知问题。看:

  • #51882调用非对象上的成员函数应引发异常
  • #46601 E_RECOVERABLE_ERROR 用于“调用非对象上的成员函数”
  • #51848非对象方法调用错误应该可以用 set_error_handler() 捕获
  • #63538 “调用未定义的函数”应该是可捕获的

有人说这是“设计使然”,但我认为这只是在将对象添加到 PHP 之前定义的错误级别的产物。在非 OO 语言中,调用不存在的函数是一个严重错误,我可以看到它可能被描述为“致命”或“不可恢复”(尽管在可以定义函数的非 OO 语言中) ——苍蝇,即使这似乎过于悲观)。现在,既然您可以$a->f()在任何 old 上执行 "" $a,那么 "" 可能不存在的可能性要大得多f,而且它似乎不应该是一个致命错误(参见 Java,这将是一个 NullPointerException)。

我想这让我想到了一个新问题:

_ 3. 您如何修补 PHP 以使“调用非对象上的成员函数”错误成为非致命错误,同时又不会严重破坏向后兼容性,以及您可以采取哪些步骤来最大限度地提高该修补程序被 PHP 接受的可能性?

更新 2重新修补 PHP:

PHP 内部邮件列表对进行此修复有一些有限的支持。现在我只需要编写一个补丁来解决这个问题并创建一个 RFC。

4

3 回答 3

4

问题是您可以动态声明对象的属性,但不能动态声明方法。因此,如果您尝试在非对象上调用方法,则会收到致命错误,因为 PHP 无法确定该函数是否存在。

检查此键盘以获取带有错误编号的一些简单输出。

现在仔细看看关于“设置和访问未设置属性”的部分。你可以看到 PHP 给你一个消息说“从空值创建默认对象”。因此,如果一个类不存在,PHP 将为您创建它。使用类型转换时也会发生同样的情况,请参阅对象类型转换

因此,您可以访问非对象的属性,因为它将在动态创建的默认对象中检查该属性。但是如果你访问一个方法,那个默认对象仍然没有那个方法。

这就是为什么属性返回 8 级错误而方法返回 1 级错误的原因(请参阅错误级别)。并且由于它返回 1 级致命错误,因此您无法在此过程之后继续。

于 2013-03-19T15:15:57.053 回答
3

这已在 PHP 7 中修复:

在 PHP 7+ 中,此代码现在将抛出,而不是导致不可恢复的致命错误。

于 2017-01-31T21:35:17.417 回答
0

我有一些好消息要告诉您:有一个名为Error Exceptions的 PHP 库可以将所有 PHP 错误转换为可捕获的异常。

这是对工作方式的一个相当大的改变,但显然你不是唯一一个想要这样做的人。

该库由 Anthony Ferrara 编写,他是 PHP 的核心开发人员之一,因此您可以相当肯定他知道他在做什么,但如果您想自己动手,它可以使用set_error_handler()函数插入到 PHP 中;如果你想捕获 PHP 的错误,你就是这样做的。

希望有帮助。

于 2013-03-19T16:59:25.550 回答