PHP - 有效的变量名称

时间:2017-02-24 18:45:58

标签: php

PHP manual on变量中,我们可以阅读:

  

变量名遵循与PHP中其他标签相同的规则。有效的变量名称以字母或下划线开头,后跟任意数量的字母,数字或下划线。作为正则表达式,它将表达为:' [a-zA-Z_ \ x7f- \ xff] [a-zA-Z0-9_ \ x7f- \ xff] *'

很明显,当我们尝试运行时:

$0-a = 5;
echo $0-a;

我们会得到Parse错误。这很明显。

然而,在尝试某些事情时,我发现实际变量在使用这样的语法时可以包含任何字符(或者至少以数字开头并包含连字符):

${'0-a'} = 5;
echo ${'0-a'};

它没有任何问题。

还使用如下变量变量:

$variable = '0-a';
$$variable = 5;
echo $$variable;

没有任何问题。

所以问题是 - 我在手册中引用的句子是不是真的,或者我所展示的这个不是真正的变量,或者它可能在PHP手册的其他地方记录了吗?

我已经验证了它 - 它似乎在PHP 5.6和7.1中都有效

另外一个问题是 - 使用这种结构是否安全?根据手册,它似乎根本不可能。

2 个答案:

答案 0 :(得分:16)

您可以为变量选择任何名称。 "i""foo"是明显的选择,但"""\n""foo.bar" 有效。原因? PHP符号表只是一个字典:零或更多字节的字符串键映射到结构化值(称为zval)。有趣的是,有两种方式来访问这个符号表:词法变量和动态变量。

词汇变量是您在"variables"文档中阅读的内容。词法变量在编译期间定义符号表键(即,当引擎处于lexing并解析代码时)。为了简化这个词法分析器,词法变量以$ sigil开头,并且必须与正则表达式[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*匹配。以这种方式保持简单意味着解析器不必弄清楚,例如,$foo.bar是由"foo.bar"键入的变量还是与常量连接的变量"foo"字符串bar

现在,动态变量就变得有趣了。动态变量允许您访问那些更不常见的变量名称。 PHP调用这些variable variables。 (我不喜欢那个名字,因为他们的对立面是逻辑上的#34;常数变量",这很令人困惑。但我在这里称它们为变量变量。)基本用法就像:

$a = 'b';
$b = 'SURPRISE!';
var_dump($$a, ${$a}); // both emit a surprise

变量变量的解析方式与词法变量不同。不是在lexing时定义符号表键,而是在运行时评估符号表键。逻辑如下:PHP词法分析器看到变量变量语法($$a或更一般${expression}),PHP解析器推迟表达式的评估,直到运行时,然后是运行时引擎使用表达式结果键入符号表。它比词汇变量更多的工作,但更强大。

${}内,你可以有一个表达式,其值为任何字节序列。空字符串,空字节,全部。什么都可以。这很方便,例如heredocs。它也可以方便地将远程变量作为PHP变量访问。例如,密钥名称中的JSON allows any character,您可能希望将它们作为直接变量(而不是数组元素)访问:

$decoded = json_decode('{ "foo.bar" : 1 }');
foreach ($decoded as $key => $value) {
    ${$key} = $value;
}
var_dump(${'foo.bar'});

以这种方式使用变量类似于将数组用作"符号表",如$array['foo.bar'],但变量变量方法完全可以接受并且速度稍快。

附录

稍快一点"到目前为止,我们正在谈论小数点的右边,它们几乎无法区分。直到10 ^ 8个符号访问,在我的测试中差异超过1秒。

Set array key: 0.000000119529
Set var-var:   0.000000101196
Increment array key: 0.000000159856
Increment var-var:   0.000000136778

失去清晰度和惯例可能不值得。

$N = 100000000;

$elapsed = -microtime(true);
$syms = [];
for ($i = 0; $i < $N; $i++) { $syms['foo.bar'] = 1; }
printf("Set array key: %.12f\n", ($elapsed + microtime(true)) / $N);

$elapsed = -microtime(true);
for ($i = 0; $i < $N; $i++) { ${'foo.bar'} = 1; }
printf("Set var-var:   %.12f\n", ($elapsed + microtime(true)) / $N);

$elapsed = -microtime(true);
$syms['foo.bar'] = 1;
for ($i = 0; $i < $N; $i++) { $syms['foo.bar']++; }
printf("Increment array key: %.12f\n", ($elapsed + microtime(true)) / $N);

$elapsed = -microtime(true);
${'foo.bar'} = 1;
for ($i = 0; $i < $N; $i++) { ${'foo.bar'}++; }
printf("Increment var-var:   %.12f\n", ($elapsed + microtime(true)) / $N);

答案 1 :(得分:1)

我在php.net(西班牙语版)上看到过$función,$año*之类的东西,所以一直想尝试,但从未尝试过。但是,由于某种原因,我写了一些变量,例如$ 1a($ 1st),$ 2a,$ 3a ...并且它起作用了,不需要'$ {1a}'或其他东西,但是,Phpstorm像这样警告我 “预期:分号”和 “表达式不可分配:常量引用”。 因此,在阅读了您在本文中的经验之后,为了使编辑器免于警告并避免将来可能出现的问题,我将所有内容都更改为$ a,$ b,$ c等。 注意:西班牙语中的$ ano(年)是肛门,因此没人喜欢使用它。