Variable Variables

Variable variables in PHP - What is their purpose?

Sometimes we need software that is extremely flexible and that we can parametrize. You have to prepare the whole thing, of course, but part of it just comes from user input, and we have no time to change the software just because the user needs a new input.

With variable variables and variable functions you can solve problems that would be much harder to solve without them.

Quick Example:


Without variable variables:


$comment = new stdClass(); // Create an object

$comment->name = sanitize_value($array['name']);
$comment->email = sanitize_values($array['email']);
$comment->url = sanitize_values($array['url']);
$comment->comment_text = sanitize_values($array['comment_text']);

With variable variables


$comment = new stdClass(); // Create a new object

foreach( $array as $key=>$val )
{
$comment->$key = sanitize_values($val);
}

Why use dynamic variables (variable variables) in PHP or other languages

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.

How do I create variable variables?

You can use dictionaries to accomplish this. Dictionaries are stores of keys and values.

>>> dct = {'x': 1, 'y': 2, 'z': 3}
>>> dct
{'y': 2, 'x': 1, 'z': 3}
>>> dct["y"]
2

You can use variable key names to achieve the effect of variable variables without the security risk.

>>> x = "spam"
>>> z = {x: "eggs"}
>>> z["spam"]
'eggs'

For cases where you're thinking of doing something like

var1 = 'foo'
var2 = 'bar'
var3 = 'baz'
...

a list may be more appropriate than a dict. A list represents an ordered sequence of objects, with integer indices:

lst = ['foo', 'bar', 'baz']
print(lst[1]) # prints bar, because indices start at 0
lst.append('potatoes') # lst is now ['foo', 'bar', 'baz', 'potatoes']

For ordered sequences, lists are more convenient than dicts with integer keys, because lists support iteration in index order, slicing, append, and other operations that would require awkward key management with a dict.

PHP - Difference in creating variable variables with brackets or double dollar signs?

Both versions are basically the same.

The curly braces notation is used in cases where there could be ambiguity:

$foo = 'bar';
$bar = [];
${$foo}[] = 'foobar';

var_dump($bar); // foobar

If you'd omit the braces in the above example, you'd get a fatal error, with the braces, it works fine.

However, I would recommend avoiding dynamic variable names altogether. They are funny to use and may save some space. But in the end, your code will become less readable and you will have trouble debugging.

Bash - variable variables

In bash, you can use ${!variable} to use variable variables.

foo="something"
bar="foo"
echo "${!bar}"

# something

Variable variables as parameters of custom function in usort()

Resolving dynamic names of variables is something that happens at runtime, rather than interpreter (aka compile) time. Therefore, you can not pass it as dynamic paramaters which you expected to be able to do.

Given that, this is not possible for one simple reason: Even if you would manage to pass different names at compile time, it would only be true for one set of values to compare. What would keep the callback-call from passing a<b, then a>b, then a==b (imagine them as values)? Nothing, and exactly that would happen.

That being said, you can try and validate which value is smaller before passing it to the final callback, but this only adds an extra layer rather than always sorting the same way (or even sorting at all):

usort($dataset, function($a, $b)
{
if ($a > $b) {
return $b <=> $a;
}
return $a <=> $b;
});

var_dump($dataset);

// output
array(3) {
[0]=>
int(3)
[1]=>
int(1)
[2]=>
int(7)
}

I am fully aware that this does not solve your problem at all. I am just trying to demonstrate that it wont even work that way.

I think the key fact here is that you define the sort mechanism in your callback, and hence you have to make sure that you sort it ascending or descending in that definition, since that is what it exists for!

And on a side note I think sorting callbacks became really easy to create in PHP since the spaceship operator:

// defines: sort ASC
usort($dataset, function($a, $b) { return $a <=> $b; });
// defines: sort DESC
usort($dataset, function($a, $b) { return $b <=> $a; });

And even more so with the arrow functions since PHP 7.4:

// ASC
usort($dataset, fn($a, $b) => $a <=> $b);
// DESC
usort($dataset, fn($a, $b) => $b <=> $a);

In conclusion, I fully understand where you are coming from, but maybe you are trying to solve a problem that is not even really there?

What's an actual use of variable variables?

Its purpose, I guess, is to allow novice programmers to dynamically change data without using "complicated stuff" like composite types (arrays and objects).

I never use them.

How to reach variable variables which has spaces?

According to the PHP docs:

A valid variable name starts with a letter or underscore, followed by any number of letters, numbers, or underscores. As a regular expression, it would be expressed thus: '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'

I.e., a variable name that contains spaces or special characters isn't a valid variable name, strictly speaking.

That being said, @mario's comment offers the workaround:

echo ${'saturday sunday'}; // echoes 'days of the weekend'

Variable variables in JavaScript

tl;dr: Don't use eval!

There is no single solution for this. It is possible to access some global variables dynamically via window, but that doesn't work for variables local to a function. Global variables that do not become a property of window are variables defined with let and const, and classes.

There is almost always a better solution than using variable variables! Instead you should be looking at data structures and choose the right one for your problem.

If you have a fixed set of names, such as

// BAD - DON'T DO THIS!!!
var foo = 42;
var bar = 21;

var key = 'foo';
console.log(eval(key));


Related Topics



Leave a reply



Submit