变量变量

有时能够使用动态变量名很方便。也就是说,可以动态设置和使用的变量名。一个正常的变量使用类似以下语句设置:

<?php
$a
= 'hello';
?>

一个变量变量使用一个变量的值并将其作为另一个变量的名称。在上面的例子中,hello 可以使用两个美元符号作为变量名,例如:

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

此时,PHP 符号表中已经定义了两个变量:$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)时,它们非常有用。

示例 #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 也是一个不能动态引用的特殊变量。

添加备注

用户贡献备注 10 个备注

546
userb at exampleb dot org
14 年前
<?php

// 甚至可以添加更多美元符号

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

$a; // 返回 Hello
$$a; // 返回 World
$$$a; // 返回 Foo
$$$$a; // 返回 Bar
$$$$$a; // 返回 a

$$$$$$a; // 返回 Hello
$$$$$$$a; // 返回 World

//... 等等 ...//

?>
11
sebastopolys at gmail dot com
1 年前
此外,可以使用关联数组来保证在函数(或类/未测试)中可用的变量名。

这样,变量变量功能对于验证变量非常有用;定义、输出和管理仅在接收参数的函数中
一个关联数组
array('index'=>'value','index'=>'value');
index = 在函数中使用的变量的引用
value = 在函数中使用的变量的名称
<?php

$vars
= ['id'=>'user_id','email'=>'user_email'];

validateVarsFunction($vars);

function
validateVarsFunction($vars){

//$vars['id']=34; <- 不起作用
// 定义允许的变量
$user_id=21;
$user_email='[email protected]';

echo
$vars['id']; // 打印变量名:user_id
echo ${$vars['id']}; // 打印 21
echo 'Email: '.${$vars['email']}; // 打印 [email protected]

// 在函数内部声明变量之前,我们没有变量名
}
?>
67
匿名
19 年前
如果变量名遵循某种“模板”,则可能值得特别注意,它们可以像这样引用。

<?php
// 假设这些变量 ...
$nameTypes = array("first", "last", "company");
$name_first = "John";
$name_last = "Doe";
$name_company = "PHP.net";

// 那么这个循环是 ...
foreach($nameTypes as $type)
print ${
"name_$type"} . "\n";

// ... 等同于这个打印语句。
print "$name_first\n$name_last\n$name_company\n";
?>

从其他人留下的笔记中可以明显看出这一点,但没有明确说明。
8
marcin dot dzdza at gmail dot com
5 年前
变量变量名的功能很受欢迎,但应尽量避免使用。现代 IDE 软件无法正确解释此类变量,常规查找/替换也会失败。这是一种魔法:) 这可能真的会使代码重构变得很困难。假设你想将变量 $username 重命名为 $userName 并尝试通过检查 "$userName" 来查找代码中 $username 的所有出现。你可能会轻易遗漏
$a = 'username';
echo $$a;
12
jefrey.sobreira [at] gmail [dot] com
9 年前
如果你想在变量变量的名称中使用一部分变量值(而不是整个名称本身),可以像下面这样操作

<?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; // 将返回 20
?>
9
Sinured
17 年前
我发现一件有趣的事情:你可以连接变量并使用空格。连接常量和函数调用也是可能的。

<?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
?>

此语法不适用于函数

<?php
$foo
= 'info';
{
"php$foo"}(); // 解析错误

// 你需要这样做:
$func = "php$foo";
$func();
?>

注意:不要省略花括号内字符串的引号,PHP 不会很好地处理它。
16
mason
14 年前
PHP 实际上支持使用变量类名调用类的新的实例,至少从 5.2 版本开始就是如此。

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

此外,你可以使用变量类名访问静态方法和属性,但只有在 PHP 5.3 之后才支持。

<?php
class Foo {
public static function
hello() {
echo
'Hello world!';
}
}
$my_foo = 'Foo';
$my_foo::hello(); // 打印 'Hello world!'
?>
8
herebepost (ta at ta) [iwonderr] gmail dot com
8 年前
虽然在日常 PHP 编程中不相关,但似乎可以在变量变量的美元符号之间插入空格和注释。所有三种注释样式都可以使用。当编写解析器、标记器或其他对 PHP 语法进行操作的东西时,此信息变得相关。

<?php

$foo
= 'bar';
$

/*
我是完全合法的,并将作为变量变量进行编译,不会出现任何通知或错误。
*/
$foo = 'magic';

echo
$bar; // 输出 magic。

?>

使用 PHP 版本 5.6.19 测试的行为
5
nils dot rocine at gmail dot com
12 年前
使用命名空间的变量类实例化

假设你有一个类,你想通过变量(使用类的名称的字符串值)对其进行实例化

<?php

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

$class = 'Foo';

$instance = new $class;

?>

上面的代码可以正常工作,除非你使用的是(已定义的)命名空间。然后你必须提供类的完整命名空间标识符,如下所示。即使实例化发生在同一个命名空间中,也是如此。正常实例化一个类(而不是通过变量)不需要命名空间。这似乎表明,如果你使用命名空间,并且在字符串中有类名,则必须提供类名对应的命名空间,才能让 PHP 引擎正确解析(其他情况:class_exists()、interface_exists() 等)。

<?php

namespace MyNamespace;

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

$class = 'MyNamespace\Foo';

$instance = new $class;

?>
5
Nathan Hammond
16 年前
这些是你在尝试动态引用超级全局变量时可能遇到的场景。它是否有效似乎取决于当前的作用域。

<?php

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

function
test() {
// NULL - 不是最初预期的那样
$string = '_POST';
var_dump(${$string});

// 按预期工作
var_dump(${'_POST'});

// 按预期工作
global ${$string};
var_dump(${$string});

}

// 按预期工作
$string = '_POST';
var_dump(${$string});

test();

?>
To Top