PHP运算符 ->{...} 的含义是什么?

16

最近我在 PHP 代码中看到了这行:

$dbObject = json_decode($jsonString);
$dbObject->{'mysql-5.4'}[0]->credentials
这是什么意思?在PHP文档中,我们可以看到:

方括号和花括号都可以互换使用来访问数组元素(例如,在上面的示例中,$array[42]和$array{42}将执行相同的操作)。

但是如何定义对象$dbObject以允许-> {...}[...]访问?这段代码是否有点不安全?哪个PHP版本支持此功能?
我在PHP文档中漏掉了什么吗?

1
请看这个链接:https://dev59.com/Z-o6XIcBkEYKwwoYTy4d - usrNotFound
1
@Dagon,原始问题并未涵盖花括号语法。这怎么可能是重复的? - feeela
有人知道这是在哪个版本的PHP中引入的吗? - user499054
有没有人有一个示例类定义,允许$dbObject->{'mysql-5.4'}[0]->credentials - WeSee
只需解码JSON字符串{"mysql-5.4":[{"credentials":1}]}(将1替换为$dbObject->{'mysql-5.4'}[0]->credentials的值)。 - Michael
5个回答

25

它的作用是使得访问某些属性不再是裸字面量,从而避免无效语法。意思是:

$dbObject->mysql-5.4[0]->credentials

这是无效/不明确的语法。为了让PHP清楚mysql-5.4是一个属性而不是一个减去浮点数的属性,您需要使用{'..'}语法。

确切地说,->{..}使您可以将任何表达式用作属性名称。例如:

$dbObject->{ sprintf('%s-%.1f', 'mysql', 5.4) }

你不能使用“-”作为属性。也许是一个神奇的属性(__get)。 - Luca Rainone
你不能使用“-”和一系列其他字符(如“.”)作为属性名称,因为它们不构成有效的变量名,会与用于运算符的其他字符产生冲突。 - deceze

5
花括号语法允许你使用字符串字面量或变量作为属性或方法名。这种方式有以下几个好处:
- 可以动态地设置属性或方法名; - 可以使用特殊字符作为属性或方法名; - 可以方便地将属性或方法名存储在变量中。
  1. (per @Deceze's answer): It allows you to access property names that would otherwise not be valid PHP syntax -- eg if the property name contains a dot or dash, per your example. Typically properties like this would be accessed via a __get() magic method, since they would also be invalid syntax to define as an actual property within the class.

  2. (per @feela's answer): It allows you to use variables to reference your properties. This is similar to the $$ variable variable syntax. It's generally not really very good practice, but is useful in some cases.

  3. (not mentioned by any other answers yet): It allows you to remove certain potential ambiguities from your code. Consider the following code for example:

    $output = $foo->$bar['baz'];
    

    This is ambiguous. You can resolve the ambiguity by adding braces or brackets:

    $output = $foo->{$bar['baz']};  //gets the value of a property from $foo which has a name that is defined in $bar['baz']
    $output = ($foo->$bar)['baz'];  //gets the ['baz'] element of $foo->$bar array.
    

    This is particularly important because the forthcoming relese of PHP 7 will change the default behaviour of code like like. This will make the language behave more consistently, but will break existing code that doesn't have the braces.

    See also the PHP documentation for this change here: https://wiki.php.net/rfc/uniform_variable_syntax

    But even without the language change to force the issue, code like this should have braces anyway to help with readability -- if you don't put braces, then you may end up struggling to work out what you were trying to do when you come back to the code in six months' time.


4
在该示例中,花括号语法不是来自数组语法,而是可能用于访问变量名的语法之一。
引用块中可以使用花括号,以清晰地界定属性名称。在访问包含数组的属性中的值时,它们最有用;当属性名称由多个部分组成或属性名称包含其他无效字符(例如来自json_decode()或SimpleXML)时,它们也很有用。
以下是来自PHP文档的示例:
echo $foo->{$baz[1]} . "\n";
echo $foo->{$start . $end} . "\n";
echo $foo->{$arr[1]} . "\n";

请参阅“PHP变量变量”:http://php.net/manual/en/language.variables.variable.php(更多用法示例在那里...)

4
作为@deceze's answer的补充: ->运算符意味着您正在访问对象属性。 在这种情况下,属性名称应该是mysql-5.4,它不是有效的PHP标识符(它必须包含字母,数字或下划线,请参见here)。 因此可以100%确定属性名称已经动态创建。
PHP允许使用名为__get()的魔术方法重载属性。 此方法的主体允许您处理任何属性 - 这可以是任何字符串,任何变量,甚至是一个强制转换为字符串的对象。
因此,在您的情况下,有人创建了一个类,并使用__get()魔术方法处理字符串mysql-5.4。 大括号{}用于表示该字符串应被视为属性名称(但是没有具有此名称的属性)。

1

大多数情况下,在->{后面会有一个$,就像->$variable

例如,我们有:

$languageCode = 'en';
$obj->{$languageCode};

$obj->{$languageCode}等同于$obj->en

============

在您的情况下,这是因为在php中不允许这样写:

$dbObject->mysql-5.4

因为在 "mysql-5.4" 中有 "-" 和 ".",而 "-" 和 "." 会把一个单词拆成两个单词。
所以你必须这样写:
$dbObject->{'mysql-5.4'}[0]->credentials

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接