Variable variables

In PHP, programmers can take advantage of an unusual technique known as variable variables. Basically, if you have a variable named $one that equals the literal integer ‘1’ and then another variable named $first that had a value of the string ‘one’, then the value of $$first would resolve as the literal integer ‘1’.

Here, check it out:

$one = 1;
$first = ‘one’;

echo $$first;
{show output}

The 2 dollar signs together are what tell PHP to return the variable $one instead of just $first. It is possibly the most confusing single thing in PHP, and something that new developers are understandably thrown by the first few times they see it. It’s not something you see a lot, but when you do see it, it’s usually because the developer was trying to solve an unusually difficult problem.

Variable variables work on both sides of an assignment too. If I were to write:

$second = ‘two’;
$$second = 2;

A new variable ‘$two’ would be added to my scope, such that if I were to say:

echo $two;

I would see ‘2’ in the output. And yes, that confuses everyone at first. I’m still confused by some of this stuff.

One of the things I find most interesting in PHP is that you can also use variables to invoke functions. Check out this example:

$test = ‘hello’;
function hello() {
echo ‘Hello World’;
}

$test();

{show output}

And so you see that I can now use a variable to invoke a function.

As far as naming restrictions, the variable $this is reserved, and can’t be used in variable variables. And with variable functions, it won’t work for special built-in PHP functions known as language constrcuts. These include ‘echo’, ‘print’, ‘isset’, ‘unset’, ’empty’, ‘include’, and ‘require’. Other than that though, you’re pretty unlimited. And variable variables don’t even need to be legal variables. Check out the following code:

$test = ‘1test’;
$$test = ‘hello’;
echo $1test; //variable names can’t begin with numbers – get a fatal parse error

You’ll get a fatal error, but if you really want to, you can do the following to see that PHP really did create your variable, you just can’t use normal PHP syntax to view it directly because of the rules around variable names. What you can do instead though, is this:

echo ${‘1test’}; //prints out ‘hello’

That last example introduced you to the power of braces in PHP. PHP can do quite a lot with braces as an intermediate step. If you place a dollar sign in front of a statement in braces, and then place an expression inbetween the braces, whether mathematical, scalar, evaluable function, whatever – if the result can be turned into a string (other than the string ‘this’), PHP will use that result as though it were the name of a variable you were attempting to access. And expressions in braces can be nested.

Though, from a practical standpoint, that’s a good way to make your code a lot harder to read!

${”} = ‘Empty!’; //the empty string can be a variable!

${${”}} = ‘Weird?’; //nesting brace expressions looks weird!

${${${”}}} = ‘Spooky!’; //double nesting just looks downright spooky!

echo ${‘Weird?’};
echo $${‘Empty!’};  //prints out ‘Spooky!Spooky!’

{show output}

Now, this last example brings up an interesting point about the empty string as a variable. Consider the following:

${null} = ‘Hello’;

echo $$notSet;

The variable $notSet was, as its name suggests, not set anywhere in the code. When PHP looks at it for the first time, it gives it an assumed value of null. Unlike more strictly-typed languages, you can use a variable in PHP without declaring it or setting a value to it. It’s just null until you make it something else. And null can be cast a string – the empty string. So here’s the output to that example:

{show output}

This leads to one way to seriously make your code confusing. When someone looks at your code for the first time, trying to understand it, one of the first things they’ll do is look to see where a particular variable is declared. But consider a script that did this:

$$somethingStrange = ‘Hello’;

//lots of intervening code

echo $$lostYa;

If neither $somethingStrange or $lostYa were declared in the code, then what you actually get is the empty string being used as a variable to save the value ‘Hello’ and then getting invoked when the script echoes $$lostYa. Here’s the output to prove it:

{show output}

Even worse, if you defined a function called ‘Hello’, then you could invoke it by doing something like:

$$somethingStrange = ‘Hello’;

function Hello() {
echo ‘Hello World. How do you suppose we got here?’;
}

$$hahaYouDontKnowWhatsGoingOn();

Hopefully you’ll never need to deliberately make your code hard to understand, but if you do, just treat the empty string variable as a part of your code, and keep invoking or setting it with a different undeclared variable every single time. I’m sure it would quickly drive me nuts if I saw it. So actually, on second thought, let me just advise you to never ever do this, but if you see it in someone else’s code, then that’s what they’ve done.

Anyway, moving back to the subject of braces, they can sometimes be the only way to resolve ambiguities, such as when your variable variables involve arrays. Consider this example with no braces:

$$one[2]

How is PHP supposed to interpet that? Do you want to get the value of $$one and then get the value at its array index 2? Or do you want to get the value of $one[2] and then use that result as a variable? Without braces, PHP can’t do anything with that expression. If you want to use $$one as your variable, use:

${$one}[2]

If you want $one[2] as your variable, use:

${$one[2]}

Here’s both examples:

{show script}
{show output}

Variable variables have been part of PHP since at least as far back as PHP 3. However, the engineers have continued to innovate, devising more ways to let you use variables in place of the names of other variables, particularly now that PHP has added so much object support.

The first one, which has been supported at least since PHP 4, is variable properties. When you refer to an object’s properties, you usually use an arrow pointing to the property name, like so:

$obj->one

However, if we again assume that the value of $first is the string ‘one’, then you can point to the same property with:

$obj->$first.

Now, that’s how it looks in PHP 5. In PHP 4 you had to place braces around your variable, like so:

$obj->{$first}

That just tells PHP to evaluate the bit inside the braces first. But since PHP 5, the engine will do that even with the braces removed (though obviously braces don’t hurt, either).

Building on that, PHP 5 also introduces the ability to refer to method calls by a variable. So, if we want the call

$obj->one()

We can now use:

$obj->$first()

Wild, isn’t it?

{show output}

The latest versions of PHP don’t even stop there. In PHP 5.3, the engineers decided to support variable class names! So, if ‘One’ is a class, and $first is the literal string ‘One’ , then the following code will create a new object of your class:

$obj = new $first();

Isn’t that cool?

I wish I could name a common problem that these techniques solve, but really, it’s just one more thing in your toolkit, and there’s no telling when you’ll reach for it. But if you know this little secret, then every so often you’ll see some tricky problem, maybe involving a sort or a switch, where variable variables turn out to be a great way to build your solution.

I know this is a difficult topic to grasp at first, but once you accept that aliasing can be used in place of actual variable and function names, it starts to make a certain sense. On the other hand, if you find yourself still not able to grasp it, I can at least reassure you that everything else in this tutorial is easier.

January 27 2010 12:27 am | Schmategories

Comments are closed.