【问题标题】:Why does the PHP parser understand "$x++-++$x", but fail on "$x+++++$x"?为什么 PHP 解析器能理解“$x++-++$x”,但在“$x+++++$x”上却失败了?
【发布时间】:2018-01-21 04:44:05
【问题描述】:

我有一个引擎,它通过从文件中获取公式、操作数和运算符来执行一些数学和逻辑运算。 所有操作都在eval 范围内执行,最终结果保存在另一个文件中。

这些文件通常通过网络传输,因此我试图通过在操作前后去除所有空格来最小化它们。 据我所知,这件事没有严格的规定,但我偶然发现了这种行为:

$x = 1;
$result = $x++-++$x; // works
$result = $x+++++$x; // fails
$result = $x++ + ++$x; // works again
  1. 为什么 PHP 对“+++++”语法感到困惑,但接受“++-++”?如何 “加号”比“减号”好吗?

  2. 是否有任何敏感操作员的列表 关于空间?

【问题讨论】:

  • 不知道答案,但我希望您真的小心您eval() 的那些输入文件,否则它们会带来巨大的漏洞
  • 对 eval 非常非常小心。这似乎是一种混乱的方式,但它仍然是一个有趣的问题。
  • @zerkms 实际上,一个 PHP 语言规范,但它的存在主要是为了体现原始实现的行为,因此像 HHVM 这样的替代方案可以作为基准。 github.com/php/php-langspec
  • 来自C,当我看到x++-++x 之类的东西时,我感到畏缩,这是教科书未定义的行为。 PHP 确定了它的含义吗?
  • “我正在尝试通过去除操作前后的所有空格来最小化它们”您是否考虑过使用 GZIP 之类的东西?

标签: php


【解决方案1】:

更多补充信息。当 PHP 脚本被“lexed”时,即当它被扫描时,包含该脚本的标记被检查。一对像“++”这样的字符表示一个增量记号,如下:

<ST_IN_SCRIPTING>"++" {
    RETURN_TOKEN(T_INC);
}

此“规则”在您下载和安装 PHP 时随附的文件 Zend/language_scanner.l 中。扫描脚本时,词法分析器可以理解关于前增量或后增量变量的唯一方法是是否存在某种分界线,例如间距,以便在上下文中正确评估每个“+”。

请注意,不建议编写如下代码:

  <?php

  $x=0;
  echo $x++ + ++$x;

即使它会被正确地使用。反对这种编码风格的原因是,对于人类大脑来说,真正发生的事情可能不太明显。评估的顺序并不是它看起来的那样,即一个变量被后递增,然后用它的预递增值添加到自身。

根据opcodes,前增量和后增量发生在之前添加发生。另外,请注意后增量返回变量的值,然后将其递增。因此,最初,$x 被赋值为 0。然后,它被后递增,以便临时变量返回值为零。然后,$x 递增以获取值 1。接下来,$x 是预先递增的,因此 $x 从值 1 移动到 2,并且其临时变量的计算结果为 2。最后加上两个临时变量,这样0 + 2 == 2;参见herehere

另外,精彩的阅读here

顺便说一句,在这种情况下,PHP 符合其前身 C 编程语言;见here

【讨论】:

    【解决方案2】:

    答案是解析器在寻找较短的标记之前先寻找较长的标记。因此 ++++++ 变成了 ++++++,这对解释器来说是不明智的。

    PHP 是从 C 中借用其表达式语法的众多语言之一,因此您可能会对这篇笔记感兴趣。在the C11 draft,第6.4节第6节给出了一个例子:

    程序片段 x+++++y 被解析为 x ++ ++ + y,这违反了对增量运算符的约束,即使解析 x ++ + ++ y 可能会产生正确的表达式。

    【讨论】:

      【解决方案3】:

      PHP 解析器在最后一个 + 符号之前搜索 ++ 符号,语法 ($x++)++ 没有意义,因为递增运算符应该应用于变量(而不是整数,是第一个$x++的结果。

      运算符操作的优先级可以在这里找到:
      http://php.net/manual/en/language.operators.precedence.php

      $x+++++$x;
      ^ php parser starts here, find $x++
          ^ here there is a new ++, which has hight precedence to the next + char
            ^ here is the last +, which the php parser will find last.
      

      ++++两个用减号分开时,代码实际上是$x++ - ++$x,PHP解析器可以理解的。

      这也是$x++ + ++$x起作用的原因。

      【讨论】:

      • 是的,确实如此。结果将与$x++ + ++$x 相同
      • 顺便说一下,这个行为的名称是“maximal munch”规则。
      猜你喜欢
      • 2021-03-16
      • 1970-01-01
      • 2020-12-04
      • 1970-01-01
      • 2020-09-04
      • 1970-01-01
      • 2023-03-19
      • 2015-05-07
      • 2016-01-16
      相关资源
      最近更新 更多