“[”如何成为 PHP 语言规范中的运算符?

How can "[" be an operator in the PHP language specification?

http://php.net/manual/en/language.operators.precedence.php 网页上,第二高优先级包含一个名为 [ 的左结合运算符。

我不明白。是 [ 用于 access/modify 数组条目,如 $myArray[23] 吗?我无法想象任何代码片段我们需要知道其他运算符的 "precedence",或者 [ 的 "associativity" 有用的地方。

在PHP中,您可以使用[]初始化空数组,因此为了了解如何定义数组,下一个字符的优先级定义了如何初始化数组。

由于数组是语法结构的一部分,它在任何数学之前完成,因此它比其他计算运算符具有更高的优先级。

var_dump([5, 6, 7] + [1, 2, 3, 4]); # 5674 - The array's must be known before applying the operator

不过老实说我不太明白这个问题。在大多数编程语言中,[] 与数组关联,数组是始终具有高优先级(如果不是最高)

的基本语法的一部分

这只是意味着数组变量(左关联性 - $first)将在数组键(右关联性 - $second)之前计算

$first[$second]

当数组具有多个维度时,这很有意义

$first[$second][$third][$fourth]

这是一个非常有效的问题。

1。 [...]

之间的优先级

首先,PHP 在查看 [ 的右侧,因为括号需要一个结束括号,所以 中间的每个运算符都优先于左括号。

示例:

$a[1+2]

+ 有优先权,即首先 1+2 必须在 PHP 确定之前计算 从 $a.

检索的元素

但是运算符优先级列表与此无关。

2。结合性

其次是评估连续对 [] 的顺序,如下所示:

$b[1][2]

PHP 将首先评估 $b[1],然后将 [2] 应用于它。这是 left-to-right 评估并且是 左结合性 .

的目的

但手头的问题与其说是结合性,不如说是关于其他运算符的优先级。

3。优先于左侧的运算符

该列表指出 clonenew 运算符优先于 [,这不容易测试。

首先,大多数将 new 与方括号组合在一起的结构都被认为是无效的 句法。例如,这两个语句:

$a = new myClass()[0];
$a = new myClass[0];

会给出解析错误:

syntax error, unexpected '['

PHP 要求您添加括号以使语法有效。所以我们无法测试 优先规则是这样的。

但还有另一种方法,使用包含 class 名称的变量:

$a = new $test[0];

这个 有效的语法,但现在的挑战是制作一个 class 来创建一些东西 就像一个数组。

这不是一件容易的事,因为对象 属性 是这样引用的:obj->prop,不是 喜欢 obj["prop"]。但是,可以使用 ArrayObject class which can deal with square brackets. The idea is to extend this class and redefine the offsetGet method 来确保 class 的新对象具有 return.

的数组元素

为了使对象可打印,我最终使用了神奇的方法 __toString,当需要将对象转换为字符串时执行该方法。

所以我想出了这个set-up,定义了两个相似的classes:

class T extends ArrayObject {
    public function __toString() {
        return "I am a T object";
    } 
    public function offsetGet ($offset)  {
        return "I am a T object's array element";
    }
}

class TestClass extends ArrayObject {
    public function __toString() {
        return "I am a TestClass object";
    } 
    public function offsetGet ($offset)  {
        return "I am a TestClass object's array element";
    }
}

$test = "TestClass";

有了这个 set-up 我们可以测试一些东西。

测试 1

echo new $test;

这条语句创建了一个新的TestClass实例,然后需要将其转换为 字符串,因此 __toString 方法在该新实例上被调用,即 returns:

I am a TestClass object

这符合预期。

测试 2

echo (new $test)[0];

这里我们从相同的操作开始,因为括号强制首先执行 new 操作。这次PHP并没有将创建的对象转换为字符串,而是从中请求数组元素0。此请求由 offsetGet 方法响应,因此上述语句输出:

I am a TestClass object's array element

测试 3

echo new ($test[0]);

这个想法是强制执行相反的顺序。可悲的是,PHP 不允许这种语法,因此必须将语句分成两部分才能获得预期的评估顺序:

$name = $test[0];
echo new $name;

所以现在先执行[,取值的第一个字符 $test,即 "T",然后 new 应用于它。这就是为什么我 还定义了一个 T class。 echo 在那个实例上调用 __toString,结果是:

I am a T object

现在进行最终测试,看看没有括号时的顺序是什么:

测试 4

echo new $test[0];

这是有效的语法,并且...

4。结论

输出为:

I am a T object

所以事实上,PHP 在 new 运算符之前应用了 [,尽管在 operator precedence table

5。比较 clonenew

clone 运算符与 [ 结合使用时具有相似的行为。奇怪的是,clonenew 在语法规则上并不完全相等。使用 clone:

重复测试 2
echo (clone $test)[0];

产生解析错误:

syntax error, unexpected '['

但是用 clone 重复的测试 4 表明 [ 优先于它。

@bishop 告知这重现了长期存在的文档错误 #61513: "clone operator precedence is wrong"