将stdClass转换为数组-键不可访问



我运行的是PHP7.0.9,当我做这样的事情:

$s = json_decode('{"1": "xxx"}');//decode json to stdClass
$a = (array)$s;//cast to array
die(var_dump($a, $a['1'], $a[1], count($a)));

我得到这样的结果:

array (size=1)
  '1' => string 'xxx' (length=3) //<-- key 1 exists
null // $a['1'] yields null
null // $a[1] doesn't work either
int 1 // count shows there is 1 element in the array

我预料到这个结果:

array (size=1)
  '1' => string 'xxx' (length=3)
string 'xxx' (length=3) // $a['1'] should work
null
int 1

我的问题:为什么我不能访问$a['1'],即使数组的countvar_dump都告诉我这个键存在?这是PHP的一个bug,还是某种特性?

引用PHP文档:

数组到对象

如果对象被转换为对象,则不会对其进行修改。如果将任何其他类型的值转换为对象,则会创建stdClass内置类的新实例。如果该值为NULL,则新实例将为空。数组转换为具有由键和相应值命名的属性的对象,但数字键例外,除非迭代,否则不可访问。

对象到数组

和类似的问题/怪癖出现在转换其他方式时:(documentation)

如果将对象转换为数组,则结果是一个数组,其元素为对象的属性。键是成员变量名,但有几个例外:整数属性不可访问;私有变量在变量名前加上类名;受保护的变量在变量名前加了一个"*"。这些前置值的两边都有空字节。这会导致一些意想不到的行为:

基本上,具有数字属性的对象可以被强制转换为数组,并且可以迭代它,但是键是不可访问的(直接)。这是一个众所周知的怪癖。您可以通过使用json_decode($string, true);立即转换为数组来绕过它,使用二次循环来"重建"数组:
$reconstructed = [];
foreach ((array) $obj as $k => $v) {
    $reconstructed[$k] = $v;
}

这是一个bug还是一个特性还不清楚。当我第一次遇到这种行为时,我称之为bug。鉴于它被记录在案并且是一个已知的怪癖,我现在认为两者都不是。它不是一个真正的bug,因为它是已知的、被理解的和有文档记录的,但它几乎不是一个特性。这只是大多数语言所具有的混乱的怪癖之一。

你必须绕过它,忍受它,避免它,处理它。考虑到PHP邮件列表中有很多关于这个问题的bug报告,并且它被添加到文档中,这个问题可能不太可能很快得到修复。

最新更新