8

I was just recently introduced to the concept of dynamic variables in PHP. To me it seems like using dynamic variables in a program would make it difficult to read/follow.

Can anyone explain to me the benefits and/or share a real simple real world example of when a dynamic variable in PHP might be needed?

If your wondering what dynamic variables are and how they work check out this question

ScottyG
  • 3,204
  • 3
  • 32
  • 42
  • 5
    They're generally referred to as variable variables; and just because they exist, doesn't mean you have to use them... generally I'd recommend not using them, because there iss always a better alternative – Mark Baker Aug 24 '17 at 16:25
  • It seems to me like it makes it difficult to read/follow, too. – Don't Panic Aug 24 '17 at 16:25
  • Based on a lot of questions here where people are trying to figure out how to use variable variables, they usually should be naming array keys instead of creating distinct variables. – Don't Panic Aug 24 '17 at 16:27
  • Thanks for the comments! I am glad I am not the only one baffled. I am sure there has to be a solid example out there somewhere, were one might absolutely need a dynamic variable, but I just can't think of one – ScottyG Aug 24 '17 at 16:32
  • I'm not using them but I can see a benefit of them. Instead of accessing the array `$SomeComplexArrayName["value"]` you can make it slightly easier and just use `$value`. – Andreas Aug 24 '17 at 16:43
  • Thanks for the comment @Andreas but I am not sure I follow? – ScottyG Aug 24 '17 at 17:07
  • @Andreas - Doesn't require variable variables to do that; just use `extract()` – Mark Baker Aug 24 '17 at 17:14

2 Answers2

6

I had voted to close this question (vote since retracted) on the basis of it being subjective, but on reflection, I think I can give an objective answer.

A static variable name is a sequence of characters, representing a token which the underlying engine uses as a label to identify the value the variable represents (very very layperson's description).

A "sequence of characters" is a string. A string is an expression that represents a string. So from there it stands to reason that any expression that represents a string ought to be good enough to represent the token that refers to a variable. And that expression itself could be assigned to a variable, and from there one gets dynamic variable names.

But this is not what you asked. You asked: why?

It's not for the implementors of the language to answer questions like that. It's their job to provide a uniform and predictable programming interface, via their language. It's uniform to be able to represent a sequence of characters via an expression which in turn could be represented by a variable. Job done.

Subjectively, I could potentially see where some data is imported from an external source, and even the schema of the data is dynamic. One might want to represent that in some sort of generic object fashion, and it leads from there that the names of the properties of the object might also be dynamic. Whether or not this might be a good approach to the problem at hand is entirely subjective, and down to the developer's judgement, and that of their peers during code review.

Another example might be that you've inherited some shoddy spaghetti code where "needs must" and using dynamic naming - for whatever reason - might be a good approach.

PHP's burden ends at providing the mechanism to write the code; it does not speak to the quality of the design of said code. That's what code review is for.

Adam Cameron
  • 29,677
  • 4
  • 37
  • 78
4

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.

Hugo Delsing
  • 13,803
  • 5
  • 45
  • 72
  • Interesting examples. It leads me to another question though, why would one use an array flip? – ScottyG Sep 07 '17 at 15:51
  • 1
    I used it in [this answer](https://stackoverflow.com/a/16521079/434949) for comparing partial similarity of two strings in PHP. Basically you use it when you have to check a lot of times if an array contains a certain value. By flipping it once, you can then use `array_key_exists` instead of constantly looping the entire array to see if it contains the value. But although this example uses `array_flip`, you can use `variable variables` when you want to do something with a lot of variables, or when you want to dynamically assign the variables you want to do it with. – Hugo Delsing Sep 07 '17 at 17:18
  • 1
    `foreach($row as $key => $val) { $$var = array_flip( $$var ); }` is simpler that `extract($row)` ? – symcbean Sep 07 '17 at 21:39
  • I think you copied the wrong part. `extract` could work on the settings example, but not array flip. But even so: Consider the settings table also has a column for id, active, modified. You can easily skip those with variable variables. For extract to work you need to drop the keys before calling it. Now obviously that is not that hard, but what if you only want to extract the fields that start with 'allow' and use the other fields for something else? This is an easy way of doing that. But i'm not here to argue there is no other way. I'm just providing examples of when you might use it. – Hugo Delsing Sep 07 '17 at 22:19