PHP: 为什么“${obj->prop}”是解析错误,而“$obj->prop”是合法的?

PHP: Why is "${obj->prop}" a parsing error, while "$obj->prop" is legal?

PHP 7.3.2

在解析 PHP 的双引号字符串中的变量时,我发现有一个解析错误很奇怪:

echo "${obj->prop}"; // Parse error: syntax error, unexpected '->' (T_OBJECT_OPERATOR)

// But this is legal:
echo "$obj->prop";

// And, for instance, all these are legal as well:
echo "${arr['key']}";
echo "${arr[0]}";
echo "${arr['0']}";

为什么口译员在${…}内对->有偏见?

首先,像这样的大括号不是复杂变量解析语法的替代形式。

"$var""${var}"是简单语法,"{$var}"是复杂语法。

在简单的语法中,解释器严格地寻找变量名,而不是表达式,花括号仅用于指示名称的结尾,以防你有类似 "${var}othertext" 的东西。手册指出

If a dollar sign ($) is encountered, the parser will greedily take as many tokens as possible to form a valid variable name. Enclose the variable name in curly braces to explicitly specify the end of the name.

解释器并没有特别反对 ${…} 中的 ->,实际上解释器对于它认为 ${…} 中的有效变量名是非常严格的,并且对访问进行了一次例外处理单个数组键。

你不能做 "${var['a']['b']}",例如。

在解释代码的第一步中,当字符串被标记化时,${ 是一个标记 T_DOLLAR_OPEN_CURLY_BRACES,它将扫描器设置为 "looking for variable name" 状态。在那种状态下,唯一会被识别为变量名的是一个有效的标签,后跟一个左方括号或右花括号。

标记数组键示例如下所示:

source: "           ${                      arr         [             'key'             ]  }  "
tokens: " T_DOLLAR_OPEN_CURLY_BRACES  T_STRING_VARNAME  [  T_CONSTANT_ENCAPSED_STRING   ]  }  "

对象 属性 示例如下所示:

source: "           ${                     obj            ->             prop    }  "
tokens: " T_DOLLAR_OPEN_CURLY_BRACES    T_STRING   T_OBJECT_OPERATOR   T_STRING  }  "

解析错误发生在下一步,将对象运算符应用于字符串,这是意外的。

使用不带大括号的简单语法,您会得到这些标记,如您所知,它们工作得很好:

source: "     $obj            ->            prop   "
tokens: "  T_VARIABLE  T_OBJECT_OPERATOR  T_STRING "