PHP与APC:致命错误:无法重新声明类

19
自从我使用PECL为PHP安装了APC后,有时会出现这些错误:Cannot redeclare class xxx xxx的名称会不时更改。虽然我可以禁用APC,但APC能够显著提高性能!是否已知此类bug或者我应该做些其他事情来防止这些错误?我正在使用Ubuntu 8.04 LTS和PHP 5.2.4。
编辑/更新(来自评论): 我使用Zend框架Autoloader,并且在启用APC之前从未出现过这些错误。例如,我刚刚遇到了这个错误:Fatal error: require(): Cannot redeclare class zend_db_adapter_abstract in /paths/app/lib/Zend/Db/Select.php on line 27

1
阅读完整的错误信息。不要两次包含同一文件。使用 include_once。如果失败,请将所有定义都包装在 if (!class_defined("xxx")) { 中。 - mario
除了仅使用include_once外,尝试重新设计应用程序以利用类自动加载,这样PHP只会在需要时包含文件。同时坚持常识性的事情,比如一个文件只有一个类等。 - Rob
1
你说的 xxx 是什么意思?xxx 真的是你想要加载的类吗? - The Surrican
我使用Zend框架自动加载器,但在启用APC之前从未出现过这些错误。就在刚才,我遇到了这个错误:Fatal error: require(): Cannot redeclare class zend_db_adapter_abstract in /paths/app/lib/Zend/Db/Select.php on line 27 - Poru
你正在运行哪个版本的APC? - Chris Henry
7个回答

13
以下配置的组合对我有所帮助,解决了这个问题:
apc.include_once_override = 0
apc.canonicalize = 0
apc.stat = 0

没有这三个东西,我会不断地收到错误提示,但有了它们,我好像不再遇到错误了 :)!


不幸的是,这三个对我都无效(APC 3.1.13 和 PHP 5.4.24 CentOS 6.5)。在 WordPress 中,它声称正在重新声明 Walker_Page 类,尽管该文件绝对没有被调用超过一次。我会深入挖掘并看看我能找到什么。 - Jason
抱歉,Jason,这适用于一些旧版本的APC和PHP。我确定当时我使用的PHP版本不会比5.3.*更新。 - Peter

12

当我启用了APC后,一些PHP库也出现了同样的问题。经过长时间的努力,我发现设置apc.include_once_override = 0可以解决问题。目前还在监控中,但是尚未出现问题(在此之前,我能够通过清除APC缓存来诱发错误)。


3
在使用运行在cron下的PHP脚本中的PHP2版本的Amazon的AWS SDK时出现了这个错误。其中一个解决方案是通过以下方式禁用apc:-d apc.enabled=0
/usr/bin/php -d apc.enabled=0 /path/to/myshelljob.php

获取更多信息


2

嗯,看起来这是一个常见问题

从您的具体错误消息中我注意到的是,您将zend_db_adapter_abstract写成了全小写。可怕的框架命名方案和自动加载器的问题在于它们以混合大小写的方式保存文件并期望如此。如果您的代码尝试以这种方式实例化它,自动加载器可能找不到它。APC在这里可能更加特殊,因为它在内部覆盖了include_once,可能会产生副作用。

解决方法是调整Zend自动加载器,并手动保留已加载的类和(绝对和小写的)文件名列表以进行校对,而不是使用include_once。

否则,请尝试进行详细的xdebug调试。由于我们无法访问您的设置,因此我们只能在这里猜测。


1

这是一个已知的APC问题,它会混淆从不同位置相对调用的include_once指令。

因此,如果您执行include_once myclass.php,然后在子目录中执行include_once ../myclass.php,APC可能会混淆并认为它们是不同的文件,并加载两次。

但是,这在后续版本中已经得到修复。

如果您可以将代码缩小到重复加载的类,您可以使用class_defined或一些可调用的内容来检查该类是否已经加载。

您还可以使用apc.filter指令来完全防止某些文件被缓存。


问题仍然存在。升级您的 APC 版本和/或 Zend Framework,否则您必须修补您的 Zend Framework,Zend 问题跟踪器上有可用的解决方案,或者您可以在应用程序中捕捉异常。 - The Surrican

1

0

我刚刚遇到了这个问题,但在其他答案中没有找到建议的解决方案。我使用各种autoloaders,包括Composer autoloader和旧版本的Zend Framework Autoloader。

问题最终被证明是由文件名和类名之间存在轻微名称不匹配引起的。类名和文件名之间只有一个字符不同 - 这是人类很容易忽略的差异,但是一些autoloaders连续地include相同的文件,导致错误发生。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接