简体   繁体   中英

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

I'm currently migrating a standard PHP project into a CakePHP framework project but am constantly coming up against this error message: Fatal error: call to member function FunctionName() on a non-object in /source/code/file.php on line XX. The old application class files are working perfectly outside of CakePHP on the exact same web server, but when copied into the CakePHP application libs folder and included I get this error message. Something seems to be affecting the scope of global variables but I've tried setting ini_set( 'register_globals', 1 ); and its made no difference at all.

Example test scenario (this is happening on all application classes like this) as follows.

Inside debug class file eg :

<?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(); }
}

Inside application files elsewhere, could be any included .php file/controller/view etc eg (normally the define and require_once lines would be in a bootstrap/config file): (通常define和require_once行位于bootstrap / config文件中):

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

When I run the above code exactly as a standalone PHP web application I get a nicely printed HTML table with a debug entry. But if I place debug.php in my libs folder and use the application file code in my layout.ctp file for example, immediate I hit the error message 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 which is the line $oDebugObj->AddEntry( array( date( 'H:i:s' ), $sName, $sValue ));

I would really appreciate if anyone can help with this. If it were just the debug function I can easily modify it to resolve this by making it just use Debug-> objcet all the time instead of Debug:: class however this method has been followed throughout the entire old project and I don't understand why this should need rewriting to function under CakePHP. Surely this must be something relatively simple to fix? Please help me out !! Thank you.

Are you including the files in global scope?

From one of your comments:

I was... including them either from view ctp files or from the bootstrap.php file in the app/config folder

This class in the question assumes that it's included in global scope ie this would work:

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

And this would not:

<?php
includeStuff() {
    include 'debug.php';
}

includeStuff();
echo Debug::Output();

In CakePHP, as soon as you leave the index.php file - you are nolonger in global scope and inferred globals such as in the code example in the question will not work.

A solution to this is to include your legacy depend-on-globals code before loading cake, in your webroot/index.php file.

Or correct/adapt the code

This relies on a global $oDebugObj to exist, and evidently when you are calling it that global doesn't exist:

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

It can be made to work without assuming the global already exists:

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 ));
}

Or just use the debug function

The class in the question doesn't look to do that much - so you could also change it to log data:

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

Or dump directly to the screen:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM