【问题标题】:How can "[" be an operator in the PHP language specification?“[”如何成为PHP语言规范中的运算符?
【发布时间】:2016-04-14 04:25:54
【问题描述】:

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

我不明白。是否是 [ 用于访问/修改数组条目,如 $myArray[23] ?我无法想象任何代码 sn-p 我们需要知道它相对于其他运算符的“优先级”,或者 [ 的“关联性”会很有用。

【问题讨论】:

    标签: php specifications


    【解决方案1】:

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

    1。 [...] 之间的优先级

    首先,在查看 [ 的右侧,因为括号需要一个闭合的来配合它,所以 介于两者之间的每个运算符都优先于左括号。

    例子:

    $a[1+2]
    

    + 具有优先权,即必须先评估 1+2,然后 PHP 才能确定哪个 要从 $a 中检索的元素。

    但运算符优先级列表不是这个。

    2。关联性

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

    $b[1][2]
    

    PHP 将首先评估$b[1],然后应用[2]。这是从左到右 左结合的意图。

    但是手头的问题不是关于关联性,而是关于其他运算符的优先级。

    3。左侧运算符的优先级

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

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

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

    会报解析错误:

    语法错误,意外'['

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

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

    $a = new $test[0];
    

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

    这并非易事,因为对象属性的引用如下:obj->prop,不是 比如obj["prop"]。但是,可以使用可以处理方括号的ArrayObject class。我们的想法是扩展这个类并重新定义offsetGet method 以确保该类的新创建的对象具有要返回的数组元素。

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

    所以我想出了这个设置,定义了两个相似的类:

    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";
    

    通过这个设置,我们可以测试一些东西。

    测试 1

    echo new $test;
    

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

    我是一个TestClass对象

    这符合预期。

    测试 2

    echo (new $test)[0];
    

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

    我是一个TestClass对象的数组元素

    测试 3

    echo new ($test[0]);
    

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

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

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

    我是T对象

    现在是最后的测试,看看没有括号时的顺序:

    测试 4

    echo new $test[0];
    

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

    4。结论

    输出是:

    我是T对象

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

    5。比较 clonenew

    clone 运算符与[ 组合具有类似的行为。奇怪的是,clonenew 在语法规则方面并不完全相等。使用 clone 重复测试 2:

    echo (clone $test)[0];
    

    产生解析错误:

    语法错误,意外'['

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

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

    【讨论】:

    • 也许还提到两个消歧变体new ($test[0])(new $test)[0]进行比较?
    • 好主意,@PaŭloEbermann。我在答案中添加了这些作为测试用例。请注意,PHP 解析器不接受第一个作为有效语法。
    • 是的,你的结论重现了一个长期存在的文档错误:bugs.php.net/bug.php?id=61513
    • 很好,@bishop,您介意我在答案中添加该引用吗?
    • 不是全部,请参考!
    【解决方案2】:

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

    $first[$second]
    

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

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

    【讨论】:

    • 感谢这个非常明确的答案!然而,这只解释了关联性的东西,而不是优先级的东西。
    • @EwanDelanoy 'Evaluated before' 是关于优先级的。这个答案中提到的关联性似乎没有意义,除非他暗示 $fourth 在 $third 等之前被评估,这也是不正确的。
    【解决方案3】:

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

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

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

    但老实说,我并不真正理解这个问题。在大多数编程语言中,[] 与数组相关联,数组是基本语法的一部分,始终具有高优先级(如果不是最高优先级)

    【讨论】:

    • 问题是:是否有任何运算符可以在表达式中[ 之前,PHP 在开始应用数组引用之前会优先应用。根据引用的文档,“新”和“克隆”将是这样的运算符。问题可能是:这有什么实际后果?
    • 显然没有,因为 new 和 clone 是语言构造函数,[] 是基本语法的一部分。如果语法有任何不一致,该文件将无法编译和执行。我会发现这是文档中的不一致,因为 new 和 clone 是实际上只不过是数组的对象。在某种程度上,[ 运算符位于 new 和 clone 之前。但是,您必须能够将算术运算符与数组一起使用,因此它优先于任何其他运算符。
    • 如何在 PHP 中“使用[] 初始化”?我使用array() 语法进行初始化,如$myArray=array(1,2,3);。当然,也可以像 $my_Array[$new_key]=$new_val; 那样添加键值对,但这适用于任何时候的任何数组,而不仅仅是最初的空数组。
    • 简单,<?php $a = []; ?>,因为我用它来节省解释器的执行时间,而且看起来更好。
    猜你喜欢
    • 1970-01-01
    • 2015-04-02
    • 2011-05-27
    • 2018-05-13
    • 1970-01-01
    • 1970-01-01
    • 2010-09-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多