如何访问具有整数或无效属性名称等名称的对象属性?针对 PHP 7.2 更新原始答案(适用于 7.2.0 之前的版本)

2022-08-30 07:37:32

我正在使用类似的东西:json_decode()

$myVar = json_decode($data)

这给了我这样的输出:

[highlighting] => stdClass Object
        (
            [448364] => stdClass Object
                (
                    [Data] => Array
                        (
                            [0] => Tax amount liability is ....... 

我想访问键 [0] 中的字符串值。当我尝试做这样的事情时:

print $myVar->highlighting->448364->Data->0;

我收到此错误:

解析错误:语法错误、意外T_DNUMBER

那里的两个数字/整数似乎有问题。


答案 1

针对 PHP 7.2 更新

PHP 7.2 引入了一个行为更改,用于在对象和数组转换中转换数字键,从而修复了这种特殊的不一致,并使以下所有示例的行为都按预期进行。

少了一件令人困惑的事情!


原始答案(适用于 7.2.0 之前的版本)

PHP有它黑暗的小巷,你真的不想发现自己在里面。名称为数字的对象属性就是其中之一...

他们从未告诉你什么

事实#1:您无法轻松访问名称不是合法变量名称的属性

$a = array('123' => '123', '123foo' => '123foo');
$o = (object)$a;
echo $o->123foo; // error

事实#2:您可以使用大括号语法访问此类属性

$a = array('123' => '123', '123foo' => '123foo');
$o = (object)$a;
echo $o->{'123foo'}; // OK!

事实#3:但如果属性名称都是数字,则不会

$a = array('123' => '123', '123foo' => '123foo');
$o = (object)$a;
echo $o->{'123foo'}; // OK!
echo $o->{'123'}; // error!

活生生的例子

事实#4:好吧,除非对象一开始就不是来自数组。

$a = array('123' => '123');
$o1 = (object)$a;
$o2 = new stdClass;
$o2->{'123'} = '123'; // setting property is OK

echo $o1->{'123'}; // error!
echo $o2->{'123'}; // works... WTF?

活生生的例子

很直观,你不同意吗?

您可以做什么

选项#1:手动操作

最实用的方法是简单地将您感兴趣的对象转换回数组中,这将允许您访问属性:

$a = array('123' => '123', '123foo' => '123foo');
$o = (object)$a;
$a = (array)$o;
echo $o->{'123'}; // error!
echo $a['123']; // OK!

不幸的是,这不能递归地工作。因此,在您的情况下,您需要执行以下操作:

$highlighting = (array)$myVar->highlighting;
$data = (array)$highlighting['448364']->Data;
$value = $data['0']; // at last!

选项#2:核选项

另一种方法是编写一个函数,以递归方式将对象转换为数组:

function recursive_cast_to_array($o) {
    $a = (array)$o;
    foreach ($a as &$value) {
        if (is_object($value)) {
            $value = recursive_cast_to_array($value);
        }
    }

    return $a;
}

$arr = recursive_cast_to_array($myVar);
$value = $arr['highlighting']['448364']['Data']['0'];

但是,我不相信这是一个更好的选择,因为它会不必要地将你不感兴趣的所有属性以及你现在的属性都强制转换为数组。

选项#3:聪明地玩

上述选项的替代方法是使用内置的 JSON 函数:

$arr = json_decode(json_encode($myVar), true);
$value = $arr['highlighting']['448364']['Data']['0'];

JSON 函数有助于执行到数组的递归转换,而无需定义任何外部函数。无论这种外观多么理想,它都有选项#2的“nuke”缺点,另外还有一个缺点,即如果对象内有任何字符串,这些字符串必须以UTF-8编码(这是json_encode的要求)。


答案 2

只是想在乔恩的雄辩解释中加入这个失败的原因。这一切都是因为在创建数组时,php会将键转换为整数 ( 如果可以的话 ) 这会导致已强制转换为对象的数组的查找问题,仅仅是因为保留了数字键。这是有问题的,因为所有属性访问选项都需要或转换为字符串。您可以通过执行以下操作来确认这一点:

$arr = array('123' => 'abc');
$obj = (object) $arr;
$obj->{'123'} = 'abc';
print_r( $obj );

这将输出:

stdClass Object ( 
  [123] => 'abc', 
  [123] => 'abc'
)

因此,该对象有两个属性键,一个数字(无法访问)和一个基于字符串的键。这就是 Jon 的工作原理,因为通过使用大括号设置属性意味着您始终定义基于字符串的键,而不是数字。#Fact 4

采用 Jon 的解决方案,但将其打开,您可以通过执行以下操作从数组中生成一个始终具有基于字符串的键的对象:

$obj = json_decode(json_encode($arr));

从现在开始,您可以使用以下任一方法,因为以这种方式访问始终将大括号内的值转换为字符串:

$obj->{123};
$obj->{'123'};

好旧的不合逻辑的PHP...


推荐