10

问题

有没有一种方法可以让 PHP忽略类的重新声明而不是抛出一个 FATAL ERROR?或者至少抛出一个异常?(然后我可以轻松地抓住它并继续(以及记录尝试的自动加载)。)

我猜不是,一个致命错误是一个致命错误——毕竟,在 100 个案例中有 99 个,这是相当明智的行为——我可能只需要修复它在案例中触发的实例——以个案为基础。但也许比我聪明的人已经想通了。


如果你问自己“你到底为什么要这么做? ”,请继续阅读。

背景

我正在开发一种工具,该工具使用反射来聚合有关使用的函数和类的特定信息。脚本的参数之一是一个可选的引导文件,以使反射在自动加载时更加可靠(更少ReflectionExceptions最终被捕获并触发回退启发式,因为特定文件中的类是未知的)。

现在,引导程序很好地加载了自动加载器,并且脚本按预期运行,毫无怨言地通过数百个文件,直到我遇到障碍:

PHP 致命错误:无法在第 62 行的 /usr/share/php/PHPUnit/Framework/Constraint.php 中重新声明类 PHPUnit_Framework_Constraint

我有两个问题:

一,我不知道是什么触发了这个。我已经调整了使用的引导程序,但仅在“无法重新声明”和“无法打开文件”之间交替,具体取决于使用的包含路径。没有中间地带,即没有不发生错误的点。不过,我还在调查。(不过,这个问题不是问题所在。)

二,更重要的是,并导致这个问题的主题,我需要一种方法来抓住它。我试过编写一个自定义错误处理程序,但它似乎不想为Fatal errors 工作(有点明智,有人可能会争辩)。

我打算在某个时候将该工具发布到开源世界中,这让我觉得这是一种非常不可接受的行为。对于不存在的类,我有一个后备启发式 - 我宁愿他们被声明一次太少而不是一次太频繁,但不要过度使用启发式,也就是说,我确实想提供使用引导程序的能力。在不破坏脚本的情况下。曾经。即使它是自动加载器历史上最糟糕的自动加载器。

(强调一下:我不想帮助我的自动装载机。这不是这个问题的目的。

4

3 回答 3

8

最好避免的选项之一Cannot redeclareclass_exists函数。您可以在自动加载器中使用它来防止类重新声明。class_exists您不必捕获错误,只需阻止它。

实际上有两种致命错误:可捕获和不可捕获。类重新声明不会触发E_RECOVERABLE_ERROR(可捕获的)并且您无法处理它。

所以,你的问题的答案是:“你不能。”

于 2010-07-14T13:46:56.783 回答
3

我不知道您是否仍然对答案感兴趣,但我可能遇到了在混合自动加载和反射时遇到的相同问题。这是我关于自动加载失败原因的假设:

spl_autoload_register区分它使用完全指定的名称空间类标识符自动加载的类,以及从名称空间内部加载的类,其类标识符不包括名称空间。据我所知,这是一个错误。

我的解决方案:我在创建反射类实例之前进行测试,如果类标识符是完全命名空间的。如果不是,我不使用反射。由于您不介意某些类未加载,因此这也可能是您问题的解决方案。

于 2013-04-12T19:58:03.160 回答
2

Autoload 永远不会自动尝试加载已经加载的类。如果您有 >1 个具有相同名称的课程,您可能做错了。

如果您解析“不安全”代码,您可能希望在尝试加载它之前搜索文件中的类名,但这只能作为最后的手段,因为它会浪费大量 CPU 并且可能只是隐藏有效的错误。

如果你有一个 require 结构和一个自动加载系统,你可能会在 autoload 中包含一个文件,然后再在 require 中包含一个文件。您可以通过使用包装类来破解修复程序if( class_exists( <class_name_string> ) { ... <class declaration in here> ... }

于 2010-07-14T14:01:36.023 回答