PHP/Codeigniter无法重新声明class-require_one,class_exists已使我失败


PHP/Codeigniter cannot redeclare class - require_once and class_exists have failed me

我在CodeIgniter支持的网站上遇到了一个令人困惑的问题。一个PHP类——TChild——会间歇性地开始抛出"cannot redclare class"错误,并破坏使用它的每个页面。我为确保声明代码只运行一次而付出的努力已经变得非常荒谬,但无济于事。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_sonce中,而且它肯定不会多次到达类定义。(然而,即使运行正常,它也会吐出两个"停止运行两次"日志条目。我不知道为什么,但至少这不会破坏任何东西。)

一旦它开始失败,它将继续破坏一切(通常)几分钟,然后由于与最初失败一样神秘的原因自行修复。

我不知道这里发生了什么。在谷歌上搜索后,我尝试将apc.enabled=0添加到php.ini中,但这对崩溃或性能都没有影响。(我不认为它一开始就被启用了,但它值得一试。)

更新:

啊哈,在第三方库中有一个require语句,它不止一次地包含了该文件。我仍然不知道为什么这个类被重新声明,尽管我在里面包了所有的if/else块,但至少现在一切都正常了。

与其只是重复文件被多次包含的事实,不如让PHP告诉你它来自哪里:

  • http://php.net/manual/en/function.debug-print-backtrace.php
  • 受John B以上评论的启发,__FILE__可能会显示您的文件不知何故有两个名称

在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)中检查文件的包含位置。