A variable variable
, is just another form of reflection. You are basically asking "Why would you ever want to change a variable, if you don't know it before runtime".
Although technically not the same, you could see a variable variable
as a different kind of hash table
(or array
in php). Most variable variables
could be rewritten as a hash table
, and you would not be surprised. But if you need to work with a variable before and after runtime, a hash table
might even be more awful to work with.
A simple use case might be settings that can be changed by a user. Keep in mind the following example is insecure as is, but demonstrates it's purpose.
<?php
/*
Simple way, if you have a limited amount of settings
*/
$settings = array();
$settings["allowAccess"] = 1;
$settings["allowModify"] = 1;
$settings["allowDelete"] = 0;
if ($result = $mysqli->query("SELECT `allowAccess`, `allowModify`, `allowDelete` FROM `user_settings` LIMIT 1"))
{
$row = $result->fetch_array(MYSQLI_ASSOC);
$settings["allowAccess"] = $row["allowAccess"];
$settings["allowModify"] = $row["allowModify"];
$settings["allowDelete"] = $row["allowDelete"];
}
/*
Now consider you have a thousand settings and you dont want to write out every setting manually.
*/
if ($result = $mysqli->query("SELECT * FROM `user_settings` LIMIT 1"))
{
$row = $result->fetch_array(MYSQLI_ASSOC);
foreach($row as $key => $val) {
$settings[$key] = $val;
}
}
/*
Both options work, but everytime you want to use a setting you have to use something like below
*/
if ($settings["allowAccess"] && $settings["allowModify"] && $settings["allowDelete"]) {
unlink($somefile);
}
/*
Perhaps you would rather write
*/
if ($allowAccess && $allowModify && $allowDelete) {
unlink($somefile);
}
/*
Then you can use
*/
if ($result = $mysqli->query("SELECT * FROM `user_settings` LIMIT 1"))
{
$row = $result->fetch_array(MYSQLI_ASSOC);
foreach($row as $key => $val) {
//if you use extract, all columns are extracted, unless you drop them first. But perhaps you need those for something else.
//now I extract the columns that start with allow and keep the columns like id, created, modified, etc. without the need to specify each column manually, which makes it easier if you ever decide to add another setting column. You don't need to update this part of the code.
if (substr($key,0,5)=='allow') {
$$key = $val; //$key = 'allowAccess', $$key == $allowAccess = $val;
}
}
}
?>
This is just one example, I found another example in the XHTML sanitizer for MediaWiki
by Brion Vibber
. He uses a lot of arrays in his code and at one point he needed to flip them all. He used the code below:
<?php
$vars = array( 'htmlpairs', 'htmlsingle', 'htmlsingleonly', 'htmlnest', 'tabletags',
'htmllist', 'listtags', 'htmlsingleallowed', 'htmlelements' );
foreach ( $vars as $var ) {
$$var = array_flip( $$var );
}
?>
Now obviously he could have written the code below, but is that really easier to read?
<?php
$htmlpairs = array_flip($htmlpairs);
$htmlsingle = array_flip($htmlsingle);
$htmlsingleonly = array_flip($htmlsingleonly);
$htmlnest = array_flip($htmlnest);
$tabletags = array_flip($tabletags);
$htmllist = array_flip($htmllist);
$listtags = array_flip($listtags);
$htmlsingleallowed = array_flip($htmlsingleallowed);
$htmlelements = array_flip($htmlelements);
?>
Which also introduces another use case: What if I wanted to dynamically decide which arrays to flip? In the variable variable
way, I can just push items onto the array and flip them when the time comes, In the "normal" way I would need a switch
or if
to loop through the array and then add each option manually.