Search code examples
phpfunctionscopeglobal-variablessuperglobals

Why does the behavior like unset() in case of global variables is not the same for other operations too?


As per the PHP documentation on unset() function :

The behavior of unset() inside of a function can vary depending on what type of variable you are attempting to destroy. If a globalized variable is unset() inside of a function, only the local variable is destroyed. The variable in the calling environment will retain the same value as before unset() was called.

The code example demonstrating above saying is as below :

<?php
function destroy_foo() 
{
    global $foo;
    unset($foo);
}

$foo = 'bar';
destroy_foo();
echo $foo; // o/p is bar
?> 

Now my question is why the above behavior is not applicable in following program that I have written?

<?php
function increment_foo() 
{
    global $foo;
    $foo++;
}

$foo = 36;
increment_foo();
echo $foo; // o/p is 37
?>

My doubt is why the behavior is different in above code than the behavior in the code written for unset() function?

In other words, I want to know in first code the unset() functionality remains limited to the local variable inside the function, it doesn't change the value in global scope outside the function but in the code that I have been written the increment functionality changes the value in global variable scope as well. In my code why it's not remaining limited to the local variable inside a function and changing value/affecting the variable outside the function as well?

Thank You.


Solution

  • The reason for this is that using the global keyword will create a local variable referencing the variable in the global scope. Unsetting simply destroys this reference. It's similar to this piece of code:

    $foo = 42;      // create variable with value
    $bar = &$foo;   // create reference to $foo
    $bar++;         // increment $foo via reference
    unset($bar);    // destroy reference
    
    var_dump($bar); // NULL
    var_dump($foo); // 43
    

    Another way to put it is that doing global $foo is just a shorthand for doing $foo = &$GLOBALS['foo'], e.g. the first example can be rewritten to

    function increment_foo() 
    {
        $foo = &$GLOBALS['foo'];
        $foo++;
        unset($foo);
        var_dump($foo); // NULL
    }
    
    $foo = 42;
    increment_foo();
    var_dump($foo); // 43
    

    Maybe that makes it more obvious that you are only destroying the reference, e.g. you are destroying what points to $foo, but not $foo itself.