我在CodeIgniter驱动的网站上遇到了一个令人困惑的问题。一个PHP类 - TChild - 将间歇性地开始抛出“无法重新声明类”错误并打破使用它的每个页面。为了确保声明代码只运行一次我已经达到的长度坦率地说是荒谬的,但无济于事。 tchild.php的顶部目前看起来像这样:
(!( isset( $GLOBALS['tchild_counter'] ) ))
? $GLOBALS['tchild_counter'] = 1
: $GLOBALS['tchild_counter']++ ;
log_message("info", "tchild has been included " . $GLOBALS['tchild_counter'] . " times");
if($GLOBALS['tchild_counter'] != 1) {
log_message("info", "STOP RUNNING TWICE");
} else {
if ( ! defined('BASEPATH')) {
log_message("error", "BASEPATH not set; no direct script access allowed");
exit('No direct script access allowed');
}
log_message("info", "Basepath is fine, checking if tchild exists (proc".getmypid().")");
log_message("info", "why does that last line seem to run twice?");
if ( ! class_exists('TChild')) {
log_message("info", "TChild does not exist, creating it");
if(class_exists('tchild')) {
log_message("info", "tchild apparently exists?");
} else {
log_message("info","okay, I'm extra-sure that tchild doesn't exist");
}
class TChild extends ActiveRecord\Model {
这是一堆巨大的...... 某事,但至少它应该确保TChild只定义一次,对吧?好吧,不。大多数情况下,它工作正常,但偶尔服务器将进入一个奇怪的状态,尽管有相反的证据,它决定TChild被宣布两次。从我添加的广泛的日志记录语句中,我相当确定tchild.php只包含一个require_once开头,并且它肯定不会多次访问类定义。 (然而,它确实会吐出两个“STOP RUNNING TWICE”日志条目,即使事情正常。我不知道为什么,但至少不会破坏任何东西。)
一旦它开始失败,它将继续(通常)几分钟内破坏所有内容,然后将其自身解决,原因与初始失败一样神秘。
我不知道这里发生了什么。谷歌搜索引导我尝试将apc.enabled = 0添加到我的php.ini,但它没有在崩溃或性能上有所作为。 (我认为它不能开始,但它值得一试。)
更新
啊哈,第三方库中有一个包含该文件不止一次的require语句。我仍然不知道为什么这个类被重新声明,尽管所有的if / else块我都把声明包裹在里面,但至少现在看来它们似乎正在工作。
答案 0 :(得分:1)
不要仅仅回应文件被包含多次的事实,而是让PHP告诉你它来自哪里:
__FILE__
可能会显示您的文件有两个名称答案 1 :(得分:0)
如何在log_message之后返回(“info”,“STOP RUNNING TWICE”);返回;或退出(0);似乎你的文件被包含多次,你永远不会停留在你的代码的任何部分。它只是到达class TChild extends ActiveRecord\Model
并再次声明的部分。
如果我只是你做的事情:
if ( ! defined('BASEPATH')) {
log_message("error", "BASEPATH not set; no direct script access allowed");
exit('No direct script access allowed');
}
if (class_exists('TChild') || class_exists('tchild')) {
log_message("info", "class already exists returning");
return; // or exit(0);
}
class TChild extends ActiveRecord\Model {
…
你问我应该检查文件的位置,除非它包含在其他一些难以追查的代码中。但上面的代码应该足够了。
您可以使用debug_backtrace
检查文件的位置,其他实用程序可以是xhprof或xdebug。