<?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
//... 以此类推 ...//
?>
有时能够使用可变变量名会很方便。也就是说,可以动态设置和使用的变量名。普通变量的设置语句如下所示:
<?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";
?>
上面的例子将输出
请注意,可变变量不能与PHP的超全局数组一起在函数或类方法中使用。$this
也是一个不能动态引用的特殊变量。
<?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
//... 以此类推 ...//
?>
此外,可以使用关联数组来确保在函数(或类/未测试)中可用的变量名。
这样,可变变量特性就可用于验证变量;仅在接收参数的函数内定义、输出和管理
一个关联数组
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]
// 在函数内声明变量之前,我们无法知道变量名
}
?>
如果变量名遵循某种“模板”,则可以像这样引用它们,这可能值得特别注意。
<?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";
?>
从其他人留下的注释中可以看出这一点,但没有明确说明。
可变变量名这个特性很受欢迎,但应尽量避免使用。现代 IDE 软件无法正确解释此类变量,常规的查找/替换也会失败。这是一种“魔法”:) 这可能会使代码重构非常困难。假设您想将变量 $username 重命名为 $userName,并尝试通过检查“$userName”来查找代码中 $username 的所有出现。您可能会很容易忽略
$a = 'username';
echo $$a;
如果您想在可变变量名称的一部分中使用变量值(而不是整个名称本身),您可以这样做:
<?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
?>
我发现一个有趣的事情:您可以连接变量并使用空格。连接常量和函数调用也是可能的。
<?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 无法很好地处理这种情况。
虽然这与日常 PHP 编程无关,但似乎可以在可变变量的美元符号之间插入空格和注释。所有三种注释样式都有效。在编写解析器、标记器或其他操作 PHP 语法的工具时,此信息将变得相关。
<?php
$foo = 'bar';
$
/*
我是完全合法的,并将作为可变变量进行编译,不会发出任何通知或错误。
*/
$foo = 'magic';
echo $bar; // 输出 magic。
?>
已在 PHP 5.6.19 版本上测试行为
至少从 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!'
?>
使用命名空间的变量类实例化注意事项
假设您有一个类,您想通过变量(使用类名的字符串值)来实例化它。
<?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;
?>
尝试动态引用超全局变量时,您可能会遇到这些情况。它是否有效似乎取决于当前作用域。
<?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();
?>