PHP致命错误:在非对象上调用成员函数,但仅当文件在CakePHP项目中使用时


PHP fatal error: Call to member function on a non-object - but only when file used inside CakePHP project?

我目前正在将一个标准PHP项目迁移到CakePHP框架项目中,但经常遇到以下错误消息:致命错误:在第XX行/source/code/file.PHP中的非对象上调用成员函数FunctionName()。旧的应用程序类文件在CakePHP之外的完全相同的web服务器上运行良好,但当复制到CakePHP应用程序libs文件夹并包含时,我会收到此错误消息。似乎有一些东西影响了全局变量的范围,但我已经尝试设置ini_set('register_globals',1);这根本没有什么区别。

示例测试场景(这发生在所有像这样的应用程序类上)如下。

调试类文件内部,例如debug.php:

<?php
class DebugObject {
  var $aDebugLog;
  var $aTemplate;
  function DebugObject( $aTemplate ) {
    $this->aDebugLog = array();
    $this->aTemplate = $aTemplate;
  }
  function AddEntry( $aEntry ) {
    if( DEBUG == true ) $this->aDebugLog[] = $aEntry;
  }
  function OutputHtml() {
    if( DEBUG == true ) {
      $sHtml = '<table style="border: 1px solid #ccc;"><tr>';
      foreach( $this->aTemplate as $rTemplate ) {
        $sHtml .= '<th style="text-align: left; font-family: Mensch; font-size: 8pt;">' . $rTemplate['name'] . '</th>';
      }
      $sHtml .= '</tr>';
      foreach( $this->aDebugLog as $aEntry ) {
        $sHtml .= '<tr>';
        $iTemplate = 0;
        foreach( $aEntry as $rEntry ) {
          $sHtml .= '<td style="border: 1px solid #ccc; padding-right: 10px; font-family: Mensch; font-size: 8pt;">' . sprintf( $this->aTemplate[$iTemplate]['format'], $rEntry ) . '</td>';
          $iTemplate++;
        }
      }
      $sHtml .= '</table>';
      return $sHtml;
    } else {
      return '';
    }
  }
}
$aTemplate = array(
  array( 'name' => 'Time', 'format' => "%-10s" ),
  array( 'name' => 'Parameter', 'format' => "%-35s" ),
  array( 'name' => 'Value', 'format' => "%-80s" )
);
$oDebugObj = new DebugObject( $aTemplate );
class Debug {
  function Add( $sName, $sValue ) { 
    global $oDebugObj;
    $oDebugObj->AddEntry( array( date( 'H:i:s' ), $sName, $sValue ));
  }
  function Output() { global $oDebugObj; return $oDebugObj->OutputHtml(); }
}

在其他地方的应用程序文件中,可以是任何包含的.php文件/controller/view等,例如test.php(通常define和require_one行将在引导程序/配置文件中):

<?php
define( 'DEBUG', true );
require_once( 'debug.php' );
Debug::Add( 'Testing', 123 );
echo Debug::Output();

当我完全作为一个独立的PHP web应用程序运行上面的代码时,我会得到一个打印得很好的HTML表,其中包含一个调试条目。但是,例如,如果我将debug.php放在libs文件夹中,并使用layout.ctp文件中的应用程序文件代码,我会立即收到错误消息Fatal error: Call to a member function AddEntry() on a non-object in /var/www/domain.com/cakephp/website/libs/debug.php on line 55,即$oDebugObj->AddEntry( array( date( 'H:i:s' ), $sName, $sValue ));

如果有人能帮忙,我将不胜感激。如果它只是调试函数,我可以很容易地修改它来解决这个问题,方法是让它一直使用Debug-> objcet,而不是Debug::类。然而,整个旧项目都遵循这种方法,我不明白为什么需要重写CakePHP下的函数。这肯定是一个相对简单的问题吗?请帮帮我!!非常感谢。

是否将文件包括在全局范围内

来自您的一条评论:

我。。。从视图ctp文件或从app/config文件夹中的bootstrap.php文件中包括它们

问题中的这一类假设它包含在全球范围内,即这将起作用:

<?php
include 'debug.php';
echo Debug::Output();

但这不会:

<?php
includeStuff() {
    include 'debug.php';
}
includeStuff();
echo Debug::Output();

在CakePHP中,一旦你离开index.php文件,你就不在全局范围内了,像问题中的代码示例中那样推断的全局将不起作用。

解决方案是在加载cake之前,在webroot/index.php文件中包含遗留的依赖全局代码。

或者更正/调整代码

这依赖于全局$oDebugObj的存在,很明显,当你调用它时,全局并不存在:

function Add( $sName, $sValue ) { 
  global $oDebugObj;
  $oDebugObj->AddEntry( array( date( 'H:i:s' ), $sName, $sValue ));
}

它可以在不假设全球已经存在的情况下工作:

function Add( $sName, $sValue ) { 
  global $oDebugObj;
  if (!$oDebugObj) {
    $aTemplate = array(
      array( 'name' => 'Time', 'format' => "%-10s" ),
      array( 'name' => 'Parameter', 'format' => "%-35s" ),
      array( 'name' => 'Value', 'format' => "%-80s" )
    );
    $oDebugObj = new DebugObject( $aTemplate );
  }
  $oDebugObj->AddEntry( array( date( 'H:i:s' ), $sName, $sValue ));
}

或者只使用调试功能

问题中的类看起来没有那么多功能,所以你也可以将其更改为日志数据:

function Add( $sName, $sValue ) { 
  CakeLog::write(LOG_DEBUG, json_encode(array($sName => $sValue)));
}

或者直接转储到屏幕:

function Add( $sName, $sValue ) { 
  debug(array($sName => $sValue));
}