PHP / Codeigniter无法重新声明类 - require_once和class_exists使我失败

时间:2012-08-22 21:45:21

标签: php codeigniter declaration

我在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块我都把声明包裹在里面,但至少现在看来它们似乎正在工作。

2 个答案:

答案 0 :(得分:1)

不要仅仅回应文件被包含多次的事实,而是让PHP告诉你它来自哪里:

答案 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检查文件的位置,其他实用程序可以是xhprofxdebug