2

I am working on a project, where global variables are used at multiple places and in various files, and have come across a situation where the value of a global variable is not what I am expecting. It would be great to know about a function which if exists, allows me to get the history of change of a global variable.

I expect that the function would allow me to get the same kind of output that we get when using debug_backtrace() with the exception that it would take the name of passed variable as an argument and will return the result with information about the line numbers and name of files where a change has been made to the global variable.

Would be a good hack to work on if such thing does not exist as of now. Thanks in advance.

Apoorv Saxena
  • 4,086
  • 10
  • 30
  • 46
  • 1
    This is where usually a debugger comes in handy. Check out e.g. [How do you debug PHP scripts?](http://stackoverflow.com/q/888) – Pekka Oct 15 '12 at 12:09
  • Such a thing does not exist. This is precisely why global variables are considered bad practice. If the global variable is an object you could build a history logging mechanism into the class, but a much better approach would be to stop using global variables. For anything. Ever. – DaveRandom Oct 15 '12 at 12:11
  • yes, I was about to say that, but removing global variables from the entire project is not possible as of now.. will try using debugger – Apoorv Saxena Oct 15 '12 at 12:16

1 Answers1

3

As already outlined this is not easily feasible. I suggest you pick yourself xdebug and work with it as a remote / step debugger. That being said, you can at least somehow do some tracking your own, but it comes with a price.

I give an example, starting with output first (here a CLI script):

GLOBAL $argv[0] changed to: /path/to/global.php
GLOBAL $argc changed to: 1
GLOBAL $test changed to: 1
GLOBAL $test changed to: 2
GLOBAL $test changed to: 3 

This has been generated by:

<?php
/**
 * @link http://stackoverflow.com/questions/12895358/how-to-check-history-of-a-global-variable-in-php
 */

declare(ticks=1);

function array_diff_recursive(array $array1, array $array2) {

    $diff = array();

    foreach ($array1 as $key => $value) {
        if (array_key_exists($key, $array2)) {
            if (is_array($value) && is_array($array2[$key])) {
                if ($result = array_diff_recursive($value, $array2[$key])) {
                    $diff[$key] = $result;
                }
            } else {
                if ($value !== $array2[$key]) {
                    $diff[$key] = $value;
                }
            }
        } else {
            $diff[$key] = $value;
        }
    }

    return $diff;
}

function globals_diff() {
    static $last = array();

    if (!isset($GLOBALS)) {
        return;
    }

    $current = array();

    $ignore = array_flip(array('_GET', '_POST', '_COOKIE', '_FILES', '_ENV', '_REQUEST', '_SERVER', 'GLOBALS'));

    foreach($GLOBALS as $key => $value) {
        isset($ignore[$key]) || $current[$key] = $value;
    }

    $diff = array_diff_recursive($current, $last);

    foreach($diff as $var => $value) {
        if (is_array($value) && $value) {
            foreach($value as $array_key => $array_value) {
                printf("GLOBAL $%s[%s] changed to: %s\n", $var, $array_key, print_r($array_value, 1));
            }
        } else {
            printf("GLOBAL $%s changed to: %s\n", $var, print_r($value, 1));
        }
    }

    $last = $current;
}

register_tick_function('globals_diff', true);

$test = 1;
$test = 2;
$test = 3;

This needs you to have ticks enabled. Otherwise you could use the global function to snapshot.

If you want to keep track of the changes over time, you need to add some other (global) data-structure to store these changes (caution, this can become large) while keeping it out of the comparison (see the ingore list).

hakre
  • 193,403
  • 52
  • 435
  • 836