I've been developing in PHP for a while now, and I still have not had a task where I've had to use variable variables. Can anyone give me examples where using them is a good idea ? Or were they included in the language just for fun ?
I generally find them in places where the code smells bad. Maybe references a static configuration variable etc... But why wouldn't the usual associative array have been a better solution. Seems like a security hole waiting to happen.
I suppose you might be able to use them in templates effectively.
First off, it'd be a huge security concern were you to use user output for these purposes. Internals are the only valid use here.
Given that, I imagine it's for things like looping through various variables, or sending variables as parameters.
foreach($name in array('_GET','_POST','_REQUEST')) {
array_map('stripslashes',$$name);
}
Unless you are working with multi-depth variables (which you won't need to if you are not doing anything fancy) you will probably don't need them. Even then, you can probably find another way to write down the same thing and still get the same result. It can be shorter (and in some cases even easier to understand) to use them though, so I for one am glad that it is part of the language.
One situation where I've had to use them is URI processing, although this technique might be dated, and I admittedly haven't used it in a long time.
Let's say we want to pull the URI from the script in the format domain.tld/controller/action/parameter/s
. We could remove the script name using the following:
$uri_string = str_replace($_SERVER['SCRIPT_NAME'], '', $_SERVER['REQUEST_URI']);
To extract the controller, action, and parameter values from this we're going to have to explode the string using the path delimiter '/'. However, if we have leading or trailing delimiters, we'll have empty array values upon explosion, so we should trim those from the beginning and end of the string:
$uri_string = trim($uri_string, '/');
We can now explode the path into an array:
$uri_data = explode('/', $uri_string);
$uri_data[0]
now contains our controller name, $uri_data[1]
contains the action name, and values in the array beyond that are parameters that should be passed to the action method.
$controller_name = $uri_data[0];
$action_name = $uri_data[1];
So, now that we have these names, we can use them for a number of things. If you keep your controllers in a very specific directory relative to the site root, you can use this information to require_once
the controller class. At that point, you can instantiate it and call it using variable variables:
$controller = new $controller_name();
$controller->{$action_name}(); // Or pass parameters if they exist
There are a lot of security gotchas to look out for in this approach, but this is one way I've seen to make use of variable variables.
DISCLAIMER: I'm not suggesting your actually use this code.
It's not uncommon for languages to include features you shouldn't touch with a bargepole (I even asked a question about it a while back), and variable variables are probably one of those constructs that fall into this category. Just because a language contains a feature doesn't mean to say you have to use it.
There may be occasions when they solve a problem (after all recursion is rarely used in practice but no-one would argue that's not an essential construct) but in general any language feature that obscures what your code is doing, and variable variables defiantly fall into this category, should be treated with extreme caution.
I haven't found many uses for variable variables but using variables for methods can be handy, as long as what you're doing is clear. For example in a simple REST service you might do something like this:
$method = $request->getMethod(); // 'post','get','put','delete'
try
{
$response = $resource->$method($request->getInput());
}
catch (BadMethodException $badMethod)
{
$response = $responseFactory->getError($badMethod);
}
Some would argue you could do this equally well with a switch
statement (which you could) but this way lends itself to extensibility (if you decide to add another method type) and maintains the abstraction of applying a method on a resource.