当我运行“Behat”步骤时,Behat error handler将“尝试获取非对象属性”错误转换为异常。
这非常有用,因为它会导致步骤被标记为失败,并允许测试运行在下一个场景中继续。
但是,“对非对象调用成员函数”错误是致命的,并立即停止测试执行(包括中止将结果写入xml)。这是无益的。
我的问题是:
这两个错误有什么区别?它们是不同的“错误级别”吗?记录在哪里?我搜索过PHP网站和Google,但找不到规范参考,只是有很多关于调试每个错误的具体实例的问题。
有没有办法将后一个错误转换为异常,而不是完全停止脚本?在我看来,用“null
”取消引用“->
”将是一个“无法恢复,例如内存分配问题”的错误。
更新
看起来这只是PHP的一个已知问题。参见:
有些人说这是“按设计”,但我认为这只是在将对象添加到PHP之前定义的错误级别的假象。在非OO语言中调用一个不存在的函数是一个严重的错误,我可以看到它如何被描述为“致命”或“不可恢复”(尽管,在非OO语言中,函数可以定义在即时,即使看起来过于悲观)。现在,既然您可以对任何旧的$a->f()
执行“$a
”,则“f
”可能不存在的可能性更大,而且似乎不应该是致命错误(参见Java,这将是一个NullPointerException)。
我想这会引出一个新问题:
_ 3.如何修补PHP以使“对非对象的成员函数调用”错误非致命,而不会大幅破坏向后兼容性,以及您可以采取哪些步骤来最大化该补丁的可能性接受PHP?
更新2 重新修补PHP:
有一些有限的支持on the PHP internals mailing list来进行此修复。现在我只需编写补丁来修复此问题并创建RFC。
答案 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的错误,你就是这样做的。
希望有所帮助。