1

我在我们的 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 中,而且它绝对不会多次到达类定义。(然而,它确实会吐出两个“停止运行两次”日志条目,即使事情运行良好。我不知道为什么,但至少这不会破坏任何东西。)

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

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

更新:

啊哈,第三方库中有一个 require 语句多次包含该文件。我仍然不知道为什么要重新声明该类,尽管我将声明包含在所有 if/else 块中,但至少现在看来一切正常。

4

2 回答 2

1

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

于 2012-08-22T23:02:37.640 回答
0

在 log_message("info", "STOP RUNNING TWICE"); 之后返回怎么样?返回; 或退出(0);似乎您的文件不止一次被包含,并且您永远不会停止代码的任何部分。它只是到达class TChild extends ActiveRecord\Modeland 再次声明的部分。

如果我在你刚刚做的地方:

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 {
…

你问我你应该检查文件是从哪里包含的,除非它是从其他一些难以追踪的代码中包含的。但是上面的代码应该足够了。您可以使用xhprofxdebugdebug_backtrace来检查您的文件包含在其他实用程序中的位置。

于 2012-08-22T22:48:10.607 回答