Search code examples
phpvariable-variables

Unexpected results using dynamic variables


The following code using switch and dynamic variables should return "b1" but it returns "11".

Is this a bug or am I doing something wrong?

<?php
$d = "Tuesday";
switch($d) {
                        case "Monday":          
            $$previousdayofmonthrow =  "a";
            $$previousdayofmonthcol =  "7";
            break;

                        case "Tuesday":             
            $$previousdayofmonthrow =  "b";
            $$previousdayofmonthcol =  "1";
            break;

                        case "Wednesday": 
            $$previousdayofmonthrow =  "b";
            $$previousdayofmonthcol =  "2";
            break;

                        case "Thursday": 
            $$previousdayofmonthrow =  "b";
            $$previousdayofmonthcol =  "3";
            break;

                        case "Friday": 
            $$previousdayofmonthrow =  "b";
            $$previousdayofmonthcol =  "4";
            break;

                        case "Saturday": 
            $$previousdayofmonthrow =  "b";
            $$previousdayofmonthcol =  "5";
            break;

                        case "Sunday": 
            $$previousdayofmonthrow =  "b";
            $$previousdayofmonthcol =  "6";
            break;
                }

    echo $$previousdayofmonthrow;
    echo $$previousdayofmonthcol;

?>

Live example > http://codepad.org/wNfCqffD


Solution

  • tldr; It is not a bug in PHP related to dynamic variables, nor is it related with the switch statement.

    The behavior of the test-case is correct and is well-defined, even if not expected.

    This is because both $previousdayofmonthrow and $previousdayofmonthcol evaluate to undefined (did have notices enabled, no?) and thus both "dynamic variables" (aka variable-variable) expressions operate on the same variable.

    Here is a minimal reproduction of the the behavior, without a switch, that also shows some interesting intermediate values:

    $x = undefined;  // The original doesn't set a value; it is implicitly undefined
    $y = undefined;  // but the effect is the same, and this way avoids warnings - yay!
    $$x = "a";
    
    echo $$x;            // -> "a"
    echo $$y;            // -> "a"
    
    $$y = "b";
    
    echo $$x;            // -> "b"
    echo $$y;            // -> "b"
    

    This "linked" behavior occurs because, as previously stated, the variable-variable expression access the same variable - mainly the variable called "undefined". (The value of the expression used as the dynamic variable name is turned into a string and "" . undefined -> "undefined"):

    echo ${"undefined"}; // -> "b"
    

    This "assignment of undefined" is allowed because undefined in PHP is a reserved word - and not a constant/variable. Thus it is not prohibited to use "undefined" as a variable name even though it cannot appear as an unquoted identifier.

    FWIW: Consider not using variable-variables; it is almost always better to use a discrete array when such "dynamic keys" are required.