可变变量

有时候使用可变变量名是很方便的。就是说,一个变量的变量名可以动态的设置和使用。一个普通的变量通过声明来设置,例如:

<?php
$a 
'hello';
?>

一个可变变量获取了一个普通变量的值作为这个可变变量的变量名。在上面的例子中 hello 使用了两个美元符号($)以后,就可以作为一个可变变量的变量了。例如:

<?php
$$a 'world';
?>

这时,两个变量都被定义了:$a 的内容是“hello”并且 $hello 的内容是“world”。因此,以下语句:

<?php
echo "$a ${$a}";
?>

与以下语句输出完全相同的结果:

<?php
echo "$a $hello";
?>

它们都会输出:hello world

要将可变变量用于数组,必须解决一个模棱两可的问题。这就是当写下 $$a[1] 时,解析器需要知道是想要 $a[1] 作为一个变量呢,还是想要 $$a 作为一个变量并取出该变量中索引为 [1] 的值。解决此问题的语法是,对第一种情况用 ${$a[1]},对第二种情况用 ${$a}[1]

类的属性也可以通过可变属性名来访问。可变属性名将在该调用所处的范围内被解析。例如,对于 $foo->$bar 表达式,则会在本地范围来解析 $bar 并且其值将被用于 $foo 的属性名。对于 $bar 是数组单元时也是一样。

也可使用花括号来给属性名清晰定界。最有用是在属性位于数组中,或者属性名包含有多个部分或者属性名包含有非法字符时(例如来自 json_decode()SimpleXML)。

Example #1 可变属性示例

<?php
class foo {
    var 
$bar 'I am bar.';
    var 
$arr = array('I am A.''I am B.''I am C.');
    var 
$r   'I am r.';
}

$foo = new foo();
$bar 'bar';
$baz = array('foo''bar''baz''quux');
echo 
$foo->$bar "\n";
echo 
$foo->$baz[1] . "\n";

$start 'b';
$end   'ar';
echo 
$foo->{$start $end} . "\n";

$arr 'arr';
echo 
$foo->$arr[1] . "\n";
echo 
$foo->{$arr}[1] . "\n";

?>

以上例程会输出:


I am bar.
I am bar.
I am bar.
I am r.
I am B.

Warning

注意,在 PHP 的函数和类的方法中,超全局变量不能用作可变变量。$this 变量也是一个特殊变量,不能被动态引用。

add a note

User Contributed Notes 48 notes

up
196
userb at exampleb dot org
6 years ago
<?php

 
//You can even add more Dollar Signs

 
$Bar = "a";
 
$Foo = "Bar";
 
$World = "Foo";
 
$Hello = "World";
 
$a = "Hello";

 
$a; //Returns Hello
 
$$a; //Returns World
 
$$$a; //Returns Foo
 
$$$$a; //Returns Bar
 
$$$$$a; //Returns a

 
$$$$$$a; //Returns Hello
 
$$$$$$$a; //Returns World

  //... and so on ...//

?>
up
29
Anonymous
11 years ago
It may be worth specifically noting, if variable names follow some kind of "template," they can be referenced like this:

<?php
// Given these variables ...
$nameTypes    = array("first", "last", "company");
$name_first   = "John";
$name_last    = "Doe";
$name_company = "PHP.net";

// Then this loop is ...
foreach($nameTypes as $type)
  print ${
"name_$type"} . "\n";

// ... equivalent to this print statement.
print "$name_first\n$name_last\n$name_company\n";
?>

This is apparent from the notes others have left, but is not explicitly stated.
up
21
J. Dyer
13 years ago
Another use for this feature in PHP is dynamic parsing.. 

Due to the rather odd structure of an input string I am currently parsing, I must have a reference for each particular object instantiation in the order which they were created.  In addition, because of the syntax of the input string, elements of the previous object creation are required for the current one. 

Normally, you won't need something this convolute.  In this example, I needed to load an array with dynamically named objects - (yes, this has some basic Object Oriented programming, please bare with me..)

<?php
  
include("obj.class");

  
// this is only a skeletal example, of course.
  
$object_array = array();

  
// assume the $input array has tokens for parsing.
  
foreach ($input_array as $key=>$value){
     
// test to ensure the $value is what we need.
        
$obj = "obj".$key;
         $
$obj = new Obj($value, $other_var);
        
Array_Push($object_array, $$obj);
     
// etc..
  
}

?>

Now, we can use basic array manipulation to get these objects out in the particular order we need, and the objects no longer are dependant on the previous ones.

I haven't fully tested the implimentation of the objects.  The  scope of a variable-variable's object attributes (get all that?) is a little tough to crack.  Regardless, this is another example of the manner in which the var-vars can be used with precision where tedious, extra hard-coding is the only alternative.

Then, we can easily pull everything back out again using a basic array function: foreach.

<?php
//...
  
foreach($array as $key=>$object){

      echo
$key." -- ".$object->print_fcn()." <br/>\n";

   }
// end foreach  

?>

Through this, we can pull a dynamically named object out of the array it was stored in without actually knowing its name.
up
23
mason
5 years ago
PHP actually supports invoking a new instance of a class using a variable class name since at least version 5.2

<?php
class Foo {
   public function
hello() {
      echo
'Hello world!';
   }
}
$my_foo = 'Foo';
$a = new $my_foo();
$a->hello(); //prints 'Hello world!'
?>

Additionally, you can access static methods and properties using variable class names, but only since PHP 5.3

<?php
class Foo {
   public static function
hello() {
      echo
'Hello world!';
   }
}
$my_foo = 'Foo';
$my_foo::hello(); //prints 'Hello world!'
?>
up
13
dlorre at yahoo dot com
6 years ago
Adding an element directly to an array using variables:

<?php
$tab
= array("one", "two", "three") ;
$a = "tab" ;
$
$a[] ="four" ; // <==== fatal error
print_r($tab) ;
?>
will issue this error:

Fatal error: Cannot use [] for reading

This is not a bug, you need to use the {} syntax to remove the ambiguity.

<?php
$tab
= array("one", "two", "three") ;
$a = "tab" ;
${
$a}[] =  "four" ; // <==== this is the correct way to do it
print_r($tab) ;
?>
up
5
aditeojr at yahoo dot co dot uk
6 years ago
Parsing and retrieving a value from superglobals, by a specified order, looping until it find one :

<?php
function GetInputString($name, $default_value = "", $format = "GPCS")
    {

       
//order of retrieve default GPCS (get, post, cookie, session);

       
$format_defines = array (
       
'G'=>'_GET',
       
'P'=>'_POST',
       
'C'=>'_COOKIE',
       
'S'=>'_SESSION',
       
'R'=>'_REQUEST',
       
'F'=>'_FILES',
        );
       
preg_match_all("/[G|P|C|S|R|F]/", $format, $matches); //splitting to globals order
       
foreach ($matches[0] as $k=>$glb)
        {
            if ( isset (
$GLOBALS[$format_defines[$glb]][$name]))
            {   
                return
$GLOBALS[$format_defines[$glb]][$name];
            }
        }
      
        return
$default_value;
    }
?>
up
8
php at ianco dot co dot uk
6 years ago
<?php
// $variable-name = 'parse error';
// You can't do that but you can do this:
$a = 'variable-name';
$
$a = 'hello';
echo
$variable-name . ' ' . $$a; // Gives     0 hello
?>

For a particular reason I had been using some variable names with hyphens for ages. There was no problem because they were only referenced via a variable variable. I only saw a parse error much later, when I tried to reference one directly. It took a while to realise that illegal hyphens were the cause because the parse error only occurs on assignment.
up
7
Sinured
8 years ago
One interesting thing I found out: You can concatenate variables and use spaces. Concatenating constants and function calls are also possible.

<?php
define
('ONE', 1);
function
one() {
    return
1;
}
$one = 1;

${
"foo$one"} = 'foo';
echo
$foo1; // foo
${'foo' . ONE} = 'bar';
echo
$foo1; // bar
${'foo' . one()} = 'baz';
echo
$foo1; // baz
?>

This syntax doesn't work for functions:

<?php
$foo
= 'info';
{
"php$foo"}(); // Parse error

// You'll have to do:
$func = "php$foo";
$func();
?>

Note: Don't leave out the quotes on strings inside the curly braces, PHP won't handle that graciously.
up
5
antony dot booth at nodomain dot here
13 years ago
You may think of using variable variables to dynamically generate variables from an array, by doing something similar to: -

<?php
foreach ($array as $key => $value)
{
  $
$key= $value;
}

?>

This however would be reinventing the wheel when you can simply use:

<?php
extract
( $array, EXTR_OVERWRITE);
?>

Note that this will overwrite the contents of variables that already exist.

Extract has useful functionality to prevent this, or you may group the variables by using prefixes too, so you could use: -

EXTR_PREFIX_ALL

<?php
$array
=array("one" => "First Value",
"two" => "2nd Value",
"three" => "8"
               
);
          
extract( $array, EXTR_PREFIX_ALL, "my_prefix_");
  
?>

This would create variables: -
$my_prefix_one
$my_prefix_two
$my_prefix_three

containing: -
"First Value", "2nd Value" and "8" respectively
up
6
the_tevildo at yahoo dot com
8 years ago
This is a handy function I put together to allow variable variables to be used with arrays.

To use the function, when you want to reference an array, send it in the form 'array:key' rather than 'array[key]'.

For example:

<?php

function indirect ($var, $value)     // Replaces $$var = $value
{
  
$var_data = $explode($var, ':');
   if (isset(
$var_data[1]))
   {
      ${
$var_data[0]}[$var_data[1]] = $value;
   }
   else
   {
      ${
$var_data[0]} = $value;
   }
}

$temp_array = array_fill(0, 4, 1);
$temp_var = 1;
$int_var_list = array('temp_array[2]', 'temp_var');

while (list(
$key, $var_name) = each($int_var_list))
{
  
//  Doesn't work - creates scalar variable called "$temp_array[2]"
  
$$var_name = 0;
}

var_dump($temp_array);
echo
'<br>';
var_dump($temp_var);
echo
'<br>';

//  Does work!

$int_var_list = array('temp_array:2', 'temp_var');

while (list(
$key, $var_name) = each($int_var_list))
{
  
indirect($var_name, 2);
}

var_dump($temp_array);
echo
'<br>';
var_dump($temp_var);
echo
'<br>';
?>
up
4
mccoyj at mail dot utexas dot edu
15 years ago
There is no need for the braces for variable object names...they are only needed by an ambiguity arises concerning which part of the reference is variable...usually with arrays.

<?php
class Schlemiel {
var
$aVar = "foo";
}

$schlemiel = new Schlemiel;
$a = "schlemiel";
echo $
$a->aVar;
?>

This code outputs "foo" using PHP 4.0.3.

Hope this helps...
- Jordan
up
3
dnl at au dot ru
15 years ago
By the way...
Variable variables can be used as pointers to objects' properties:

<?php
class someclass {
  var
$a = "variable a";
  var
$b = "another variable: b";
  }

$c = new someclass;
$d = "b";
echo
$c->{$d};
?>

outputs: another variable: b
up
3
nullhility at gmail dot com
7 years ago
It's also valuable to note the following:

<?php
${date("M")} = "Worked";
echo ${
date("M")};
?>

This is perfectly legal, anything inside the braces is executed first, the return value then becomes the variable name. Echoing the same variable variable using the function that created it results in the same return and therefore the same variable name is used in the echo statement. Have fun ;).
up
5
Nathan Hammond
8 years ago
These are the scenarios that you may run into trying to reference superglobals dynamically. Whether or not it works appears to be dependent upon the current scope.

<?php

$_POST
['asdf'] = 'something';

function
test() {
   
// NULL -- not what initially expected
   
$string = '_POST';
   
var_dump(${$string});

   
// Works as expected
   
var_dump(${'_POST'});

   
// Works as expected
   
global ${$string};
   
var_dump(${$string});

}

// Works as expected
$string = '_POST';
var_dump(${$string});

test();

?>
up
1
coviex at gmail dot com
2 years ago
In 5.4 "Dynamic class references require the fully qualified class name (with the namespace in it) because at runtime there is no information about the current namespace." is still true.
Neither simple class name nor containing subnamespace works.
Initial source: //bugs.php.net/bug.php?id=45197
up
2
Omar Juvera
4 years ago
The example given in the php manual is confusing!
I think this example it's easier to understand:

<?php

//Let's create a new variable: $new_variable_1
$var_name = "new_variable_1"; //$var_name will store the NAME of the new variable

//Let's assign a value to that [$new_variable_1] variable:
$$var_name  = "value 1"; //Value of $new_variable_1 = "value 1"

echo "VARIABLE: " . $var_name;
echo
"<br />";
echo
"VALUE: " . $$var_name;
?>

The OUTPUT is:
VARIABLE: new_variable_1
VALUE: value 1

You can also create new variables in a loop:
<?php

for( $i = 1; $i < 6; $i++ )
{
$var_name[] = "new_variable_" . $i; //$var_name[] will hold the new variable NAME
}

${
$var_name[0]}  = "value 1"; //Value of $new_variable_1 = "value 1"
${$var_name[1]}  = "value 2"; //Value of $new_variable_2 = "value 2"
${$var_name[2]}  = "value 3"; //Value of $new_variable_3 = "value 3"
${$var_name[3]}  = "value 4"; //Value of $new_variable_4 = "value 4"
${$var_name[4]}  = "value 5"; //Value of $new_variable_5 = "value 5"

echo "VARIABLE: " . $var_name[0] . "\n";
echo
"<br />";
echo
"VALUE: " . ${$var_name[0]};
?>

The OUTPUT is:
VARIABLE: new_variable_1
VALUE: value 1
up
2
jupp-mueller at t-online dot de
13 years ago
I found another undocumented/cool feature: variable member variables in classes. It's pretty easy:

<?php
class foo {
  function
bar() {
   
$bar1 = "var1";
   
$bar2 = "var2";
   
$this->{$bar1}= "this ";
   
$this->{$bar2} = "works";
  }
}

$test = new foo;
$test->bar();
echo
$test->var1 . $test->var2;
?>
up
2
thien_tmpNOSPAM at hotmail dot com
13 years ago
You can also use variable variables and the string concat operator to generate suffixed (or prefixed) variables based on a base name.

For instance, if you wanted to dynamically generate this series of variables:

base1_suffix1
base1_suffix2
base2_suffix1
base2_suffix2
base3_suffix1
base3_suffix2

You can do this:

<?php
$bases
= array('base1', 'base2', 'base3');
$suffixes = array('suffix1', suffix2);
foreach(
$bases as $base) {
    foreach(
$suffixes as $suffix) {
        ${
$base.$suffix} = "whatever";
       
#...etc
   
}
}
?>
up
3
chrisNOSPAM at kampmeier dot net
14 years ago
Note that normal variable variables will not be parsed in double-quoted strings. You'll have to use the braces to make it work, to resolve the ambiguity. For example:

<?php
$varname
= "foo";
$foo = "bar";

print $
$varname// Prints "bar"
print "$$varname"// Prints "$foo"
print "${$varname}"; // Prints "bar"
?>
up
1
jefrey.sobreira [at] gmail [dot] com
1 year ago
If you want to use a variable value in part of the name of a variable variable (not the whole name itself), you can do like the following:

<?php
$price_for_monday
= 10;
$price_for_tuesday = 20;
$price_for_wednesday = 30;

$today = 'tuesday';

$price_for_today = ${ 'price_for_' . $today};
echo
$price_for_today; // will return 20
?>
up
2
bpotier at edreamers dot org
15 years ago
A good example of the use of variable variables name. Imagine that you want to modify at the same time a list of more than one record from a db table.
1) You can easily create a dynamic form using PHP. Name your form elements using a static name and the record id
ex: <input name="aninput<?php echo $recordid?>" which gives in the output something like <input name="aninput15">

2)You need to provide to your form action/submit script the list of records ids via an array serialized and urlencoded via an hidden field (to decode and un serialize once in the submit script)

3) In the script used to submit you form you can access the input value by using the variable ${'aninput'.$recordid} to dynamically create as many UPDATE query as you need

[Editor Note: Simply use an array instead, for example: <input name="aninput[<?php echo $recordid?>]" And loop through that array. -Philip]
up
3
nils dot rocine at gmail dot com
3 years ago
Variable Class Instantiation with Namespace Gotcha:

Say you have a class you'd like to instantiate via a variable (with a string value of the Class name)

<?php

class Foo
{
    public function
__construct()
    {
        echo
"I'm a real class!" . PHP_EOL;
    }
}

$class = 'Foo';

$instance = new $class;

?>

The above works fine UNLESS you are in a (defined) namespace. Then you must provide the full namespaced identifier of the class as shown below. This is the case EVEN THOUGH the instancing happens in the same namespace. Instancing a class normally (not through a variable) does not require the namespace. This seems to establish the pattern that if you are using an namespace and you have a class name in a string, you must provide the namespace with the class for the PHP engine to correctly resolve (other cases: class_exists(), interface_exists(), etc.)

<?php

namespace MyNamespace;

class
Foo
{
    public function
__construct()
    {
        echo
"I'm a real class!" . PHP_EOL;
    }
}

$class = 'MyNamespace\Foo';

$instance = new $class;

?>
up
2
j3nda at fv dot cz
8 years ago
hi, i handling multi-array with like this:

i use this for some classes with direct access to $__info array. and i have some config_{set|get} static functions without this class, but handling is the same.

i'm not testing this piece of code for benchmark and high load.

<?php
class __info {
  private
$__info=array();

  public function
__s($value=null, $id='')
    {
        if (
$id == '')
            return
false;

       
$id='[\''.$id.'\']';
        for (
$i=2, $max=func_num_args(), $args=func_get_args(); $i<$max; $i++)
           
$id.='[\''.$args[$i].'\']';

        eval(
'
            if (isset($this->__info'
.$id.')) {
                // debug || vyjimka
            }
            $this->__info'
.$id.'=$value;
        '
);
        return
true;
    }

  public function
__g($id)
    {
       
$uid='';
        for (
$i=0, $max=func_num_args(), $args=func_get_args(); $i<$max; $i++)
           
$uid.="[\'".$args[$i]."\']";

        return eval(
'
            if (isset($this->__info'
.$uid.')) {
                return $this->__info'
.$uid.';

            } else {
                return false;
            }
            // debug || vyjimka
        '
);

        return
false;
    }
?>
up
2
fabio at noc dot soton dot ac dot uk
10 years ago
A static variable variable sounds like an oxymoron and indeed cannot exist. If you define:

<?php
$var
= "ciao";
static $
$var = 0;
?>

you get a parse error.
Regards,

Fabio
up
1
moomin
6 years ago
If $something is 'myvar' then you can use $obj->{"_$something"} to get the value of $obj->_myvar without having to use eval.
up
1
nick at customdesigns dot ca
7 years ago
On the topic of variable variables with arrays, I have a simple function that solves the issue. It works for both indexed and associative arrays, and allows use with superglobals.

<?php
function VariableArray($arr, $string)
    {
   
preg_match_all('/\[([^\]]*)\]/', $string, $arr_matches, PREG_PATTERN_ORDER);
   
   
$return = $arr;
    foreach(
$arr_matches[1] as $dimension)
        {
       
$return = $return[$dimension];
        }
       
    return
$return;
    }

$test = array('one' => 'two', 'four' => array(8));

$foo = 'test';
$bar = $$foo;
$baz = "[one]";
$var = VariableArray($bar, $baz); //$var now contains 'two'

$baz = "[four][0]";
$var = VariableArray($bar, $baz); //$var now contains int(8)
?>

You can simply pass in a superglobal as the first argument. Note for associative arrays don't put quotes inside the square braces unless you adjust the regexp to accept it. I wanted to keep it simple.
up
1
Anonymous
7 years ago
I have a HTML form that has a dynamic number of fields (for entry of collected data it adds a new field each time) and would like to use the variable variable on _POST.  This way, I could increment the field name value with a loop limit when say 100 fields are reached (the max for the form.)

Below is the solution I came up with to work around it:

<?php
        $MaxRows
=100;
       
$NumbersOfTime=0;
       
extract ($_POST,EXTR_PREFIX_ALL,'pos');

        for (
$i = 1; $i <= $MaxRows; $i = $i + 1)
        {
               
$tmp = "pos_TimeRecorded{$i}";
                if (isset($
$tmp))
                {
                       
$TimeRecorded[$i]=$$tmp;

                }
                else
                {
                       
$NumbersOfTime=$i-1;
                        break;
                }
        }

?>
up
1
Aycan Yat
2 years ago
Sometimes you might wish to modify value of an existing variable by its name. This is easily accomplishable with a combination of using "passing by reference" and "variable variables".

$first_var = 1;
$second_var = 2;
$third_var = 3;

$which_one = array_rand('first', 'second', 'third');
//Let's consider the result is "second".

$modifier = $$which_one;  //Now $modifier has value 2.
$modifier++; //Now $modifier's value is 3.
echo $second_var; //Prints out 2

//Consider we wish to modify the value of $second_var
$modifier = &$$which_one;  //Simply passing by reference
$modifier++; //Now value of $second_var is 3 too.
echo $second_var; //Prints out 3

It's that simple!
up
1
Omar Juvera
4 years ago
In this example, I have the variable $city.
To store the variable $city inside another variable:

<?php
$city
= 'New York';

$var_container = 'city'; //$var_container will store the variable $city

echo "CONTAINER's var: " . $var_container;
echo
"<br />";
echo
"CONTAINER's value: " . $$var_container;
echo
"<br />";
echo
"VAR city: " . $city;
?>

The OUTPUT is:
CONTAINER's var: city
CONTAINER's value: New York
VAR city: New York
up
1
craigmorey at gmail dot com
8 years ago
For a long time I've been trying to use variable variables to figure out how to store and retrieve multi-dimensional arrays in a MySQL dbase. For instance, a config setting stored in a complex array might resemble the below:

<?php $config['modules']['module_events']['settings']['template']['name'] = 'List Page'; ?>

The most obvious way for storing this info in a dbase (discounting XML/JSON) is to store a "path" (of the nesting) and a "value" in a database record:

'modules,module_events,settings,template,name' = 'List Page'

But storing it is only part of the problem. PHP variable variables are no use to try and interpret string representations of arrays, eg it will see the string representation of a nested array such as config['modules']['module_events'] as a single variable called 'config[modules][module_events]', so loops that parse the "path" into a variable variable don't help.

So here is a little function that parses an array of "paths" and "value" strings (eg from a dbase) into a multi-dimensional nested array.

<?php
function multiArrayMe($input_array) {
   
$output_array = array();
   
# common sense check
   
if (!is_array($input_array)) {
        return
false;
    }
   
# loop through the array of "path"=>"value"
   
foreach ($input_array AS $key1 => $val1) {
       
       
# explode the path to find the list of nested keys
       
$temp1 = explode(',',$key1);
       
# if this path isn't an array, skip this cycle
       
if (!is_array($temp1)) {
            continue;
        }
       
# reverse sort the keys so we'll start building from
        # the bottom, not the top
       
krsort($temp1);
       
# start with the temporary array off with the end value
       
$temp2 = $val1;
       
# loop through the nested keys
       
foreach($temp1 AS $val2) {
           
# if this nested key has no name,
            # (and isn't "0") skip this cycle
           
if ($val2===false) {
                continue;
            }
           
# gradually build up the this temporary nested array
            # from the leaf, working up the branches to the trunk
           
$temp2 = array($val2 => $temp2);
        }
       
# for this cycle, dump this bucketful of data into the bathtub
       
$output_array = array_merge_recursive($output_array,$temp2);
    }
    return
$output_array;
}
?>
up
1
correojulian33-php at yahoo dot es
8 years ago
This example may help to overcome the limitation on $this.

Populate automatically fields of an object form a $_GET variable.

<?php
class pp{
   var
$prop1=1,$prop2=2,$prop3=array(3,4,5);

   function
fun1(){
     
$vars=get_class_vars('pp');
      while(list(
$var,$value)=each($vars)){
              
$ref=& $this->$var;
              
$ref=$_GET[$var];

      }
// while
     
var_dump($this);
   }
}

$_GET['prop1']="uno";
$_GET['prop2']="dos";
$_GET['prop3']=array('tres','cuatro','cinco','seis');

$p=new pp();
$p->fun1();
?>

output is ...

object(pp)#1 (3) {
  ["prop1"]=>
  &string(3) "uno"
  ["prop2"]=>
  &string(3) "dos"
  ["prop3"]=>
  &array(4) {
    [0]=>
    string(4) "tres"
    [1]=>
    string(6) "cuatro"
    [2]=>
    string(5) "cinco"
    [3]=>
    string(4) "seis"
  }
}
up
1
sir_hmba AT yahoo DOT com
13 years ago
This is somewhat redundant, but I didn't see an example that combined dynamic reference of *both* object and attribute names.

Here's the code:

<?php
class foo
{
    var
$bar;
    var
$baz;

    function
foo()
    {
       
$this->bar = 3;
       
$this->baz = 6;
    }
}

$f = new foo();
echo
"f->bar=$f->bar  f->baz=$f->baz\n";

$obj  = 'f';
$attr = 'bar';
$val  = $$obj->{$attr};

echo
"obj=$obj  attr=$attr  val=$val\n";
?>

And here's the output:

f->bar=3  f->baz=6
$obj=f  $attr=bar  $val=3
up
0
cgray at metamedia dot us
2 years ago
Returning values from a multidimensional array based using variable variables
and infinite key depth

I banged my head against this but could not find a way in language structure or
in functions to retreive a value from a multidimensional array where the key
path is known as a variable string. I considered some sort of recursive
function, but it seemed cumbersome for what should be a one-liner.

My solution uses eval() to return the array value:

<?php

$geolocation
= array("ip"=>"127.0.0.1", "location" => array("city" =>
"Knoxville", "state_province" => "TN", "country" => "USA"));

print_r($geolocation); // Array ( [ip] => 127.0.0.1 [location] => Array ( [city]
=> Knoxville [state_province] => TN [country] => USA ) )

// typical use of variable variables
$key = "ip";
$result = $geolocation[$key];
print_r($result); // 127.0.0.1

$key = "location"; // another typical use of variable variables
$result = $geolocation[$key];
print_r($result); // Array ( [city] => Knoxville [state_province] => TN
[country] => USA )

// but how do we go deeper? this does NOT work
$key = "location['city']";
// $result = $geolocation[$key]; // Notice: Undefined index: location['city']
// print_r($result);

// this does NOT work
$key = "['location']['city']";
// $result = $geolocation{$key}; // Notice: Undefined index: ['location']
['city']
// print_r($result);

// this works:
$key = "['location']['city']";
$result = eval('echo $geolocation'."$key;");
print_r($result); // Knoxville

?>
up
-2
cottton at i-stats dot net
1 year ago
<?php
$key       
= 'post';
$type       = '_'.strtoupper($key);
$copy       = ${$type}; // is a copy of $_POST

// btw:
$reference  = &${$type}; // is a ref to $_POST
?>
up
0
mot at tdvniikp dot ru
10 years ago
You can simple access Globals by variable variables in functions, example:
<?php
function abc() {
   
$context = '_SESSION';

    global $
$context;
    if(isset($
$context)) {
       
var_dump($$context);
    }
}
abc();
?>
up
0
rafael at fuchs inf br
11 years ago
You can use constants in variable variables, like I show below. This works fine:

<?php
define
("TEST","Fuchs");
$Fuchs = "Test";

echo
TEST . "<BR>";
echo ${
TEST};
?>

output:

Fuchs
Test
up
0
Anonymous
13 years ago
The 'dollar dereferencing' (to coin a phrase) doesn't seem to be limited to two layers, even without curly braces.  Observe:

<?php
$one
= "two";
$two = "three";
$three = "four";
$four = "five";
echo $$$
$one; //prints 'five'.
?>

This works for L-values as well.  So the below works the same way:

<?php
$one
= "two";
$
$one = "three";
$$
$one = "four";
$$$
$one = "five";
echo $$$
$one; //still prints 'five'.
?>

NOTE: Tested on PHP 4.2.1, Apache 2.0.36, Red Hat 7.2
up
0
mstearne at entermix dot com
15 years ago
Variable variables techniques do not work when one of the "variables" is a constant.  The example below illustrates this.  This is probably the desired behavior for constants, but was confusing for me when I was trying to figure it out.  The alternative I used was to add the variables I needed to the $GLOBALS array instead of defining them as constants.

<?php

define
("DB_X_NAME","database1");
define("DB_Y_NAME","database2");
$DB_Z_NAME="database3";


function
connectTo($databaseName){
global
$DB_Z_NAME;

$fullDatabaseName="DB_".$databaseName."_NAME";
return ${
$fullDatabaseName};

}

print
"DB_X_NAME is ".connectTo("X")."<br>";
print
"DB_Y_NAME is ".connectTo("Y")."<br>";
print
"DB_Z_NAME is ".connectTo("Z")."<br>";

?>
[Editor Note: For variable constants, use constant() --Philip]
up
-1
andre at AWizardOfAss dot com
5 years ago
To generate a family of variables, such as $a1, $a2, $a3, etc., one can use "variable variables" as follows:

<?php
for ($i = 1; $i <= 5; $i++) {
  ${
a.$i} = "value";
}   

echo
"$a1, $a2, $a3, $a4, $a5";
//Output is value, value, value, value, value
?>

Note that the correct syntax is ${a.$i} rather than the perhaps more intuitive $a{$i}

The dot (.) is the string concatenation operator.

A family of variables might be used as an alternative to arrays.
up
-1
David Forger
2 years ago
Parse an imported string e.g. from a database for php variable names and replace them with their values.

example:
In the String "Dear $firstname $lastname, welcome to our Homepage" the variables shall be replaced with the respective values.

<?php
$welcome
= getImportedString();
$firstname = "David";
$lastname = "Forger";

echo
$welcome;
// before replacement output will be:
//"Dear $firstname $lastname, welcome to our Homepage"

function replaceVars($match) {
       return
$GLOBALS[$match[1]];
}       
$welcome = preg_replace_callback('/\$(\w+)/i', "replaceVars", $welcome);

echo
$welcome;
//now output will be:
//"Dear David Forger, welcome to our Homepage"
?>
up
-1
ckelley at ca-cycleworks dot com
4 years ago
Unlike as stated near the bottom of this thread, using variables to point to an object does not always work. In my case, that is the object returned from `new SimpleXMLElement($xmlstr)`.

Once my nodes got 3 and 4 deep to access customer information from orders, I knew something drastic had to be done.

<?php
$xmlstr
="<xml><foo><bar><you>Blah</you></bar></foo></xml>";

$xml=SimpleXMLElement($xmlstr);
// no matter what you feed it, it works...
$lvl1="\$xml->foo";
echo
n($lvl1."->bar->you");

// n will return Blah as we would hope.

function n($node){
    global
$xml;
    return eval(
"return $node;"); 
}

?>
up
-1
Sam Yong - hellclanner at live dot com
5 years ago
Want to access object's property or array value using variable variables but not possible?

Here's a workaround to it:

<?php

function varvar($str){
    if(
strpos($str,'->') !== false){
     
// Accessing object property
       
$parts = explode('->',$str);
        global ${
$parts[0]};
        return ${
$parts[0]}->$parts[1];
    }elseif(
strpos($str,'[') !== false && strpos($str,']') !== false){
       
$parts = explode('[',$str);
        global ${
$parts[0]};
       
$parts[1] = substr($parts[1],0,strlen($parts[1])-1);
        return ${
$parts[0]}[$parts[1]];
    }else{
        global ${
$str};
        return ${
$str};
    }
}

$arrayTest = array('value0', 'value1', 'test1'=> 'value2', 'test2'=> 'value3');
$objectTest = (object)$arrayTest;

$test = 'arrayTest[1]';
var_dump(varvar($test)); // string(6) "value1"
var_dump($$test); // NULL

$test2 = 'objectTest->test2';
var_dump(varvar($test2)); // string(6) "value3"
var_dump($$test2); // NULL

?>

Cheers
Sam-Mauris Yong
up
-1
al at o3strategies dot com
6 years ago
This is an extremely handy use for variable variables especially when dealing with direct data modeling.  This will allow you to automatically set object properties based on a query result. When new fields are added to the table, the class will receive these properties automatically. This is great for maintaining user data or other large tables. Your property names will be bound to your column name in the database, making maintenance worry free. This method uses $this->{$var} for the variable variable creation.

<?php
class testTableData() {

    function
testTableData(){ 
       
// testTable includes the columns: name, user, date
       
$query = "SELECT * FROM testTable";     
       
$result = mysql_query($query) or die (mysql_error());
       
$row = mysql_fetch_array($result);
        foreach (
$row as $var => $key) {
           
$this->{$var} = $key;
        }   
    }

}

// Access table properties
$table = new testTableData();

echo
$table->name;
echo
$table->user;
echo
$table->date;

?>
up
-1
espertalhao04 at hotmail dot com
2 years ago
a tiny code to set variables if they don't have value yet:
<?php
   
function setvar($n,$v){global$$n;if(!isset($$n))$$n=$v;}
?>
this works under any scope, even when called inside another function!
up
-1
Shawn Beltz
11 years ago
Multidimensional variable variables.  If you want to run the below as one big program, you'll have to undefine $foo in between assignments.

<?php

$foo
= "this is foo.";
$ref = "foo";
print $
$ref;
# prints "this is foo."

$foo[1]['a_z'] = "this is foo[1][a_z].";
$ref = "foo[1][a_z]";
print $
$ref;
# Doesn't print anything!

$foo = "this is foo.";
$ref = "foo";
$erf = eval("return \$$ref;");
print
$erf;
# prints "this is foo."

$foo[1]['a_z'] = "this is foo[1][a_z].";
$ref = "foo[1][a_z]";
$erf = eval("return \$$ref;");
print
$erf;
# prints "this is foo[1][a_z]."

?>
up
-3
aneesiqbalbhatti at gmail dot com
2 years ago
<?php
$he
= 'loves';
$loves = 'you';
$you = 'he';
echo $$
$he." ".$$$$he." ".$$he;
up
-5
Matthew (mwwaygoo AT hotmail DOT com)
6 years ago
A note on Variable variables/functions and classes

To store a function name in a variable and call it later, within a class, you do the following:-

<?php

class test_class
{
    var
$func='display_UK'// function name *
   
   
function display_UK()
    {
        echo
"Hello";
    }
    function
display_FR()
    {
        echo
"Bonjour";
    }
    function
display()
    {
       
$this->{$this->func}(); // NOTE the brackets MUST be here and not in the function name above *
   
}

}

$test=new test_class();
$test->display_UK(); // to test they work directly
$test->display_FR();
$test->display();
?>

This allows you to specify the function required. It works better then a big switch statement as it allows for extending the class more easily. (ie adding display_ES(); )
up
-3
php at willshouse dot the-usual-uk-tld
6 years ago
If you need to access one of the superglobals using a variable variable, you can look it up in $GLOBALS:

<?PHP
define
('FORM_METHOD', 'post');

function
getFormVariable( $fieldName, $defaultValue )
{
    global
$FILTER_METHOD;
   
$getpost = $GLOBALS[ '_' . strtoupper(FILTER_METHOD) ];
    if ( !
array_key_exists( $fieldName, $getpost    ) )    { return $defaultValue; }
    if ( empty(   
$getpost[ $fieldName ]            ) )    { return $defaultValue; }
    return
$getpost[ $fieldName ];
}

echo
"<form method=\"".FORM_METHOD."\">\n";
?>