2024年PHP日本大会

可变变量

有时能够使用可变变量名会很方便。也就是说,可以动态设置和使用的变量名。普通变量的设置语句如下所示:

<?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条注释

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

//... 以此类推 ...//

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

这样,可变变量特性就可用于验证变量;仅在接收参数的函数内定义、输出和管理
一个关联数组
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]

// 在函数内声明变量之前,我们无法知道变量名
}
?>
匿名用户
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";
?>

从其他人留下的注释中可以看出这一点,但没有明确说明。
marcin dot dzdza at gmail dot com
5年前
可变变量名这个特性很受欢迎,但应尽量避免使用。现代 IDE 软件无法正确解释此类变量,常规的查找/替换也会失败。这是一种“魔法”:) 这可能会使代码重构非常困难。假设您想将变量 $username 重命名为 $userName,并尝试通过检查“$userName”来查找代码中 $username 的所有出现。您可能会很容易忽略
$a = 'username';
echo $$a;
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
?>
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 无法很好地处理这种情况。
herebepost (ta at ta) [iwonderr] gmail dot com
8年前
虽然这与日常 PHP 编程无关,但似乎可以在可变变量的美元符号之间插入空格和注释。所有三种注释样式都有效。在编写解析器、标记器或其他操作 PHP 语法的工具时,此信息将变得相关。

<?php

$foo
= 'bar';
$

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

echo
$bar; // 输出 magic。

?>

已在 PHP 5.6.19 版本上测试行为
mason
14年前
至少从 5.2 版本开始,PHP 实际上支持使用变量类名来调用类的新的实例。

<?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!'
?>
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;

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