If the debugger is not available, you can use pure PHP code. Here is an option using the small helper class CSysTracer.
Based on this interface:
abstract class CSTReportDelegate { abstract public function emitVariableChange( $variableName, $oldValue, $newValue ); abstract public function emitVariableSetNew( $variableName, $newValue ); }
created this particular instance
class CSTSimpleReportDelegate extends CSTReportDelegate { public function emitVariableChange( $variableName, $oldValue, $newValue ) { echo '<br />[global/change] '. $variableName . ' : ' . print_r( $oldValue, true ) . ' → ' . print_r( $newValue, true ); } public function emitVariableSetNew( $variableName, $newValue ) { echo '<br />[global/init] '. $variableName . ' → ' . print_r( $newValue, TRUE ); } }
... pass it to CSysTracer:
CSysTracer::setReportDelegate( new CSTSimpleReportDelegate() );
... and activate agent tracking using this:
CSysTracer::start( 5 );
While CSTSimpleReportDelegate is outputting output, it can write material to a log file and, for example, make selective entries on certain statements.
Note that this version of CSysTracer tracks global variable changes. Rewriting it to record each statement is simple enough.
CSysTracer does the trick using the PHP tick function :
class CSysTracer { static protected $reportDelegate; static private $globalState = array(); static private $traceableGlobals = array(); static private $globalTraceEnabled = FALSE; const DEFAULT_TICK_AMOUNT = 1; static public function setReportDelegate( CSTReportDelegate $aDelegate ) { self::$reportDelegate = $aDelegate; } static public function start( $tickAmount = self::DEFAULT_TICK_AMOUNT ) { register_tick_function ( array( 'CSysTracer', 'handleTick' ) ); } static public function stop() { unregister_tick_function( array( 'CSysTracer', 'handleTick' ) ); } static public function evalAndTrace( $someStatement ) { declare( ticks = 1 ); { self::start(); eval( $someStatement ); self::stop(); } } static public function addTraceableGlobal( $varName ) { if ( is_array( $varName )) { foreach( $varName as $singleName ) { self::addTraceableGlobal( $singleName ); } return; } self::$traceableGlobals[ $varName ] = $varName; } static public function removeTraceableGlobal( $varName ) { unset( self::$traceableGlobals[ $varName ] ); } static public function handleTick( ) { if ( TRUE === self::$globalTraceEnabled ) { self::traceGlobalVariable(); } } static public function enableGlobalsTrace() { self::$globalTraceEnabled = TRUE; } static public function disableGlobalsTrace() { self::$globalTraceEnabled = FALSE; } static public function traceGlobalVariable( ) { foreach( self::$traceableGlobals as $aVarname ) { if ( ! isset( $GLOBALS[ $aVarname ] )) { continue; } if ( ! isset( self::$globalState[ $aVarname ] ) ) { self::$reportDelegate->emitVariableSetNew( $aVarname, $GLOBALS[ $aVarname ] ); self::$globalState[ $aVarname ] = $GLOBALS[ $aVarname ]; continue; } if ( self::$globalState[ $aVarname ] !== $GLOBALS[ $aVarname ]) { self::$reportDelegate->emitVariableChange( $aVarname, self::$globalState[ $aVarname ], $GLOBALS[ $aVarname ] ); } self::$globalState[ $aVarname ] = $GLOBALS[ $aVarname ]; } } }