PHP转向"调用非对象上的成员函数"变成例外

时间:2013-03-19 14:43:05

标签: php error-handling

当我运行“Behat”步骤时,Behat error handler将“尝试获取非对象属性”错误转换为异常。

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

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

我的问题是:

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

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

  3. 更新

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

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

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

    我想这会引出一个新问题:

    _ 3.如何修补PHP以使“对非对象的成员函数调用”错误非致命,而不会大幅破坏向后兼容性,以及您可以采取哪些步骤来最大化该补丁的可能性接受PHP?

    更新2 重新修补PHP:

    有一些有限的支持on the PHP internals mailing list来进行此修复。现在我只需编写补丁来修复此问题并创建RFC。

3 个答案:

答案 0 :(得分:4)

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

检查this codepad是否有错误编号的简单输出。

现在仔细看看关于“Set and acces unset property”的部分。你可以看到PHP给你一条消息“从空值创建默认对象”。因此,如果一个类不存在,PHP将为您创建它。使用类型转换时会发生同样的情况,请参阅object typecasting

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

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

答案 1 :(得分:1)

这已在PHP 7中修复:

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

答案 2 :(得分:0)

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

对于工作方式来说,这是一个相当戏剧性的改变,但显然你不是唯一一个想要做到这一点的人。

lib是由Anthony Ferrara编写的,他是PHP核心开发人员之一,所以你可以相当肯定他知道自己在做什么,但是如果你想自己做,它会使用{{{{{{ 3}};如果你想捕获PHP的错误,你就是这样做的。

希望有所帮助。