Search code examples
phpglobal-variablessuperglobals

Global variable not updating inside static Class method in PHP


I have a problem with global variables in PHP. My problem is that a global variable that I change inside a static class method isn't updating outside the method.

I've included the code:

test.php

define( 'APP_ID', 'TESTING' );
$_APP = array( 'test' => 'test value' );
include ('appsettings.class.php');
AppSettings::initApplication();

appsettings.class.php

class AppSettings
{
  public static function initApplication()
  {
    global $_APP;
    session_start();

    // Some code here for your initializtions
    self::initAppEngine();
echo '<pre>Inside initApplication: '; print_r($_APP);
echo '<pre>Directly printing the session variable: '; print_r($_SESSION[APP_ID] );
  }

  private static function initAppEngine()
  {
    global $_APP;

    if( isset($_SESSION[APP_ID]) )
    {
      $_APP = &$_SESSION[APP_ID];
    }
    else
    {
      $_SESSION[APP_ID] = array( 'abcd' => 'hello', 'APP_ID' => APP_ID );
      $_APP = &$_SESSION[APP_ID];
die("Refresh the page");
    }

    if ( !isset( $_APP['uid'] ) )
      $_APP['uid'] = 0;

echo '<pre>Inside initAppEngine: '; print_r($_APP);
  }
}

The old value of $_APP is coming instead of the new one inside initApplication. Can anyone point out what I'm doing wrong?

Thanks in advance,


Solution

  • This is quite interesting. First of all, note that it seems to have nothing to do with static methods:

    $_SESSION['test'] = array("test value from superglobal");
    $_APP = array('test' => "test value directly assigned");
    
    class AppSettings
    {
      public static function initApplication()
      {
        global $_APP;
        $_APP = &$_SESSION['test'];
        echo '<pre>Inside initApplication: '; print_r($_APP);
      }
    
      public function initApplicationNonStatic()
      {
        global $_APP;
        $_APP = &$_SESSION['test'];
        echo '<pre>Inside initApplicationNonStatic: '; print_r($_APP);
      }
    }
    
    echo '<pre>Before calling initApplication: '; print_r($_APP);
    AppSettings::initApplication();
    echo '<pre>After calling initApplication: '; print_r($_APP);
    echo '<pre>Before calling initApplicationNonStatic: '; print_r($_APP);
    $appSettings = new AppSettings();
    $appSettings->initApplicationNonStatic();
    echo '<pre>After calling initApplicationNonStatic: '; print_r($_APP);
    

    Result:

    Before calling initApplication: Array
    (
        [test] => test value directly assigned
    )
    Inside initApplication: Array
    (
        [0] => test value from superglobal
    )
    After calling initApplication: Array
    (
        [test] => test value directly assigned
    )
    Before calling initApplicationNonStatic: Array
    (
        [test] => test value directly assigned
    )
    Inside initApplicationNonStatic: Array
    (
        [0] => test value from superglobal
    )
    After calling initApplicationNonStatic: Array
    (
        [test] => test value directly assigned
    )
    

    But this works:

    $_SESSION['test'] = array("test value from superglobal");
    $_APP = array('test' => "test value directly assigned");
    
    class AppSettings2
    {
      public function initApplicationNonStatic()
      {
        $GLOBALS['_APP'] = &$_SESSION['test']; // by reference
        echo '<pre>Inside initApplicationNonStatic: '; print_r($GLOBALS['_APP']);
      }
    }
    
    echo '<pre>Before calling initApplicationNonStatic: '; print_r($_APP);
    $appSettings2 = new AppSettings2();
    $appSettings2->initApplicationNonStatic();
    echo '<pre>After calling initApplicationNonStatic: '; print_r($_APP);
    $_SESSION['test'] = array("test value from superglobal altered");
    echo '<pre>After altering superglobal: '; print_r($_APP);
    

    Result:

    Before calling initApplicationNonStatic: Array
    (
        [test] => test value directly assigned
    )
    Inside initApplicationNonStatic: Array
    (
        [0] => test value from superglobal
    )
    After calling initApplicationNonStatic: Array
    (
        [0] => test value from superglobal
    )
    After altering superglobal: Array
    (
        [0] => test value from superglobal altered
    )
    

    And this works, too:

    $_SESSION['test'] = array("test value from superglobal");
    $_APP = array('test' => "test value directly assigned");
    
    class AppSettings2
    {
      public function initApplicationNonStatic()
      {
        global $_APP;
        $_APP = $_SESSION['test']; // by value
        echo '<pre>Inside initApplicationNonStatic: '; print_r($_APP);
      }
    }
    
    echo '<pre>Before calling initApplicationNonStatic: '; print_r($_APP);
    $appSettings2 = new AppSettings2();
    $appSettings2->initApplicationNonStatic();
    echo '<pre>After calling initApplicationNonStatic: '; print_r($_APP);
    $_SESSION['test'] = array("test value from superglobal altered");
    echo '<pre>After altering superglobal: '; print_r($_APP);
    

    Result:

    Before calling initApplicationNonStatic: Array
    (
        [test] => test value directly assigned
    )
    Inside initApplicationNonStatic: Array
    (
        [0] => test value from superglobal
    )
    After calling initApplicationNonStatic: Array
    (
        [0] => test value from superglobal
    )
    After altering superglobal: Array
    (
        [0] => test value from superglobal // expected, since assigned by value
    )
    

    So, it seems that whenever you want to assign a reference to a global variable inside a function or method, you have to use the $GLOBALS['_APP'] syntax and you cannot use global $_APP. If you don't need the assignment by reference, $GLOBALS['_APP'] and global $_APP behave the same.

    I'm not exactly sure why this is so; some pages refer to the equivalence of these two constructs:

    global $example;
    $example =& $GLOBALS['example'];
    

    This might lead to the right track; however, I hope that you can troubleshoot your problem with my answer.