可変変数
変数名を可変にできると便利なことが時々あります。可変変数では、変数 名を動的にセットし使用できます。通常の変数は、次のような命令でセッ トします。
<?php
$a = 'hello';
?>
可変変数は、変数の値をとり、変数の名前として扱います。上の例では、 hello は、ドル記号を二つ使用することにより、 変数の名前として使用することができます。つまり、
<?php
$$a = 'world';
?>
ここまでで、二つの変数が定義され、PHP シンボルツリーに定義されてい ます。これらは、"hello" を値とする$aと "world" を値とする$helloです。そこで、次の命令
<?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 に由来するプロパティ) などです。
例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";
?>
上の例の出力は以下となります。
I am bar.
I am bar.
I am bar.
I am r.
関数やクラスメソッドの内部で、可変変数と PHP の
スーパーグローバル配列 とを組み合わせては使用できないということに注意してください。
$this
も特別な変数であり、
動的に参照することはできません。
User Contributed Notes 10 notes
<?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 ...//
?>
In addition, it is possible to use associative array to secure name of variables available to be used within a function (or class / not tested).
This way the variable variable feature is useful to validate variables; define, output and manage only within the function that receives as parameter
an associative array :
array('index'=>'value','index'=>'value');
index = reference to variable to be used within function
value = name of the variable to be used within function
<?php
$vars = ['id'=>'user_id','email'=>'user_email'];
validateVarsFunction($vars);
function validateVarsFunction($vars){
//$vars['id']=34; <- does not work
// define allowed variables
$user_id=21;
$user_email='email@mail.com';
echo $vars['id']; // prints name of variable: user_id
echo ${$vars['id']}; // prints 21
echo 'Email: '.${$vars['email']}; // print email@mail.com
// we don't have the name of the variables before declaring them inside the function
}
?>
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.
The feature of variable variable names is welcome, but it should be avoided when possible. Modern IDE software fails to interpret such variables correctly, regular find/replace also fails. It's a kind of magic :) This may really make it hard to refactor code. Imagine you want to rename variable $username to $userName and try to find all occurrences of $username in code by checking "$userName". You may easily omit:
$a = 'username';
echo $$a;
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
?>
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.
While not relevant in everyday PHP programming, it seems to be possible to insert whitespace and comments between the dollar signs of a variable variable. All three comment styles work. This information becomes relevant when writing a parser, tokenizer or something else that operates on PHP syntax.
<?php
$foo = 'bar';
$
/*
I am complete legal and will compile without notices or error as a variable variable.
*/
$foo = 'magic';
echo $bar; // Outputs magic.
?>
Behaviour tested with PHP Version 5.6.19
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!'
?>
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;
?>
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();
?>