backend, Dec 3, 20185 min read

How to: Variable variables

While browsing through some obscure part of your project code, maybe you’ve come by a variable starting with a double-dollar sign (eg. $$example). Those variables are called variable variables (check the documentation).

What they basically do is take the value you assigned to them and treat it as another variable’s name. This means that by calling a variable with double dollar sign in front of it, you are actually working with the value of the variable whose name is the value of the first variable. Let’s look at the following example to clear things up:

$bar = "foo";
$foo = 10;
echo $$bar; // prints: 10

The variable $bar has the value “foo”, and $foo variable has the value 10. If we echo $$bar, it will print out 10, the value of $foo variable. To understand this, you need to understand how PHP handles variables. PHP is written in C language, and every variable (among other data) you allocate is represented by a structure called zval:

struct _zval_struct {
    zvalue_value value;     /* value */
    zend_uint refcount__gc;
    zend_uchar type;        /* active type */
    zend_uchar is_ref__gc;
};

In the zval structure the value field represents the variable’s value. type field represents the variable type (integer, string etc.). refcount__gc and is_ref_gc fields are related to memory management. refcount__gc is an integer indicating how many variables point to the current variable. is_ref__gc is an integer that represents a boolean value, and when set to 1 it means that the current variable is a reference. The variables form example above are represented with the following zval structures:

How does $$bar variable get the value 10?

The answer is in the name of PHP. It’s a recursive acronym meaning Hypertext Preprocessor. In that way, we will ignore the Hypertext part at the moment and focus on Preprocessor. Preprocessor commands, in general, are invoked by the compiler to process some parts of code before its compilation. Preprocessor directives change the text of the source code and the result is a new source code without these directives.

PHP is a preprocessor interpreter, which means that it parses and compiles the code during runtime, so basically, all PHP commands are preprocessor commands. This means that at some point all your variables will be replaced with their value.

Taking that into account, the variable $$bar from the example will behave in the following way during the dynamic preprocessing:

This is all fine and dandy, but complicated to go through in your head while programming. But, if you ever used C programming language, you are surely familiar with the concept of pointers. Written below is an example of pointer usage in C language:

int foo = 10;
int *bar = &foo;
printf("%d",*bar); //prints: 10

A pointer variable in C (*bar in the example) is a variable whose value is a memory address of another data. By setting the value of the bar variable to the memory address location of the foo variable, bar variable becomes a pointer to foo variable.

If we were to print bar without the asterix (*) we would see the memory address of foo variable on the screen. By printing out bar variable as a pointer (with asterix), we see the value of foo variable, ie. the value of the variable the pointer is pointing to.

Back to the PHP example

If we think of a variable name as it’s address, we can see the similarities between the two examples. If we would echo $bar variable we would get ‘foo’ as a result, but by echoing $$bar, we will get the value of $foo variable. This makes the $bar variable a makeshift pointer to $foo variable. This analogy makes it easier to read variable variables and exactly know their value at any given time.

There are various ways in which variable variables can be used, some of them listed in the example below:

class Foo
{
    public static $foo = 'This is static foo';
    public $foo2 = 'This is foo class property';

    public function getFoo()
    {
        return 'This is an output from class method';
    }

    public function __toString()
    {
        return 'Foo';
    }
}

$bar = 'foo';
$foo = 'This is foo outside of the class';

echo Foo::$$bar; //prints: This is static foo

echo $$bar; //prints: This is foo outside of the class

$fooClass = new Foo();
$bar2 = 'foo2';

echo $fooClass->$bar2; //prints: This is foo class property

$bar3 = 'getFoo';
echo $fooClass->$bar3(); //prints: This is an output from class method

As you can see from the example, variable variables can be used to access other variables, static variables and even other class’s properties. Just make sure to note that variables (or methods) that you wouldn’t add the dollar sign in front of when you call them (eg. $this->foo), will not have two dollar signs in front of them, but one.

Also, it is wise to implement an asset method for the variables you are trying to get, as your desired variable might not actually be set.

Are variable variables actually needed?

To be fair, variable variables as such are not exactly needed in everyday PHP programming, there are some usages that can come in handy. Imagine that you have a lot of possible user roles in your project.

User roles are usually some ugly strings that are easy to handle but don’t look very good to the user. But your users want to see their role displayed somewhere, and they don’t want to see the ugly role name that you save to your database. You would probably solve this easily with a few conditions. But let’s take advantage of our new knowledge of variable variables and solve the problem using them:

class UserRoles
{
    public static $ROLE_ADMIN = 'Administrator';
    public static $ROLE_SUPER_ADMIN = 'Super Administrator';
    public static $ROLE_USER = 'User';
    public static $ROLE_SOME = 'Some role';
    public static $ROLE_OTHER = 'Other role';
}

$roles = ['ROLE_ADMIN', 'ROLE_SUPER_ADMIN', 'ROLE_USER', 'ROLE_OTHER'];

foreach ($roles as $role) {
    echo UserRoles::$$role;
}

/**
 * prints:
 * Administrator
 * Super Administrator
 * User
 * Other role
 */

Using variable variables instead of conditions brings our call to a single line. It’s not just that it’s simple, but it is almost 1.8 times faster than writing conditions for every role (measured on 2 million iterations). This usually occurs due to the fact that it is faster to change the variables into their values during preprocessor interpretation than to actually execute conditions during the execution of the program.

These examples covered only the basic usages of variable variables, but you can easily find others by just Google-ing them. They are a quite a nifty little thing if you know what you are doing.

Before using variable variables in your code be sure you know exactly how they behave and what their values are at every point of execution. If used improperly, variable variables can cause security issues on your application, or make it difficult to read, so use them with caution.

There we go, that sums up one of the easiest ways to tackle variables. All in all, if you have any questions or suggestions on how to improve the content we display, feel free to let us know!


You liked this? Give Danijela a .

48