如何使用整数等名称访问对象属性?

avi*_*hah 85 php properties object

如何访问输出为的PHP Associative数组元素:

[highlighting] => stdClass Object
        (
            [448364] => stdClass Object
                (
                    [Data] => Array
                        (
                            [0] => Tax amount liability is ....... 
Run Code Online (Sandbox Code Playgroud)

我想访问键[0]中的字符串值.我想做的事情如下:

print myVar->highlighting->448364->Data->0
Run Code Online (Sandbox Code Playgroud)

但这两个数字/整数似乎有问题.

编辑:

我将在这里给出一些历史,从哪里获得myVar.我使用的json_decode()是:

$myVar = json_decode(url)
Run Code Online (Sandbox Code Playgroud)

Jon*_*Jon 276

针对PHP 7.2进行了更新

PHP 7.2引入了一个行为更改来转换对象和数组转换中的数字键,这修复了这种特殊的不一致性,并使以下所有示例都按预期运行.

少搞一点!


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

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

他们从未告诉过你什么

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

$a = array('123' => '123', '123foo' => '123foo');
$o = (object)$a;
echo $o->123foo; // error
Run Code Online (Sandbox Code Playgroud)

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

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

事实#3:不是如果属性名称是全数字!

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

实例.

事实#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?
Run Code Online (Sandbox Code Playgroud)

实例.

非常直观,你不同意吗?

你可以做什么

选项#1:手动完成

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

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

不幸的是,这不会递归地起作用.因此,在您的情况下,您需要执行以下操作:

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

选项#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'];
Run Code Online (Sandbox Code Playgroud)

但是,我并不相信这是一个更好的选择,因为它会不必要地将所有你感兴趣的属性和你自己的属性一起转换为数组.

选项#3:玩得很聪明

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

$arr = json_decode(json_encode($myVar), true);
$value = $arr['highlighting']['448364']['Data']['0'];
Run Code Online (Sandbox Code Playgroud)

JSON函数有助于执行到数组的递归转换,而无需定义任何外部函数.不过这看起来很可取,它具有选项#2的"核"缺点,另外还有一个缺点,即如果你的对象中有任何字符串,那些字符串必须用UTF-8编码(这是一个要求json_encode).

  • @Pacerier:我同意这有点可疑,但在某些情况下它完全有意义.无论如何,因为手册中的[记录](http://php.net/manual/en/language.types.object.php#language.types.object.casting)就像这样工作,我们的个人意见不会真的很重要. (4认同)
  • **事实 #0**:将数组转换为对象一开始就不应该没有任何意义。事实#1 到事实#3:不需要。 (2认同)

Peb*_*bbl 10

只是想加入Jon的雄辩解释,说明失败的原因.这一切都是因为在创建数组时,php会将键转换为整数 - 如果可以的话 - 这会导致已经转换为对象的数组上的查找问题,这只是因为数字键被保留了.这是有问题的,因为所有属性访问选项都期望或转换为字符串.您可以通过执行以下操作来确认:

$arr = array('123' => 'abc');
$obj = (object) $arr;
$obj->{'123'} = 'abc';
print_r( $obj );
Run Code Online (Sandbox Code Playgroud)

哪个会输出:

stdClass Object ( 
  [123] => 'abc', 
  [123] => 'abc'
)
Run Code Online (Sandbox Code Playgroud)

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

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

$obj = json_decode(json_encode($arr));
Run Code Online (Sandbox Code Playgroud)

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

$obj->{123};
$obj->{'123'};
Run Code Online (Sandbox Code Playgroud)

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


ume*_*dam 5

对于 PHP 7

访问以数字作为属性名称的对象属性。

在将数组转换为对象之后,最需要它。

    $arr = [2,3,7];
    $o = (object) $arr;

    $t = "1";
    $t2 = 1;
    $t3 = (1);

    echo $o->{1};     // 3
    echo $o->{'1'};   // 3
    echo $o->$t;      // 3
    echo $o->$t2;     // 3
    echo $o->$t3;     // 3

    echo $o->1;       // Error
    echo $o->(1);     // Error
Run Code Online (Sandbox Code Playgroud)