Search code examples
phpjsonphp-7stdclass

casting stdClass to array - keys not accessible


I'm running PHP7.0.9, when I do something like this:

$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)));

I get this result:

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

I was expecting this result:

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

My question: Why can't I access $a['1'], even though both countand a var_dump of the array tell me that this key exists? Is this a bug in PHP, or some kind of feature?


Solution

  • Quoting the PHP documentation:

    Array to object

    If an object is converted to an object, it is not modified. If a value of any other type is converted to an object, a new instance of the stdClass built-in class is created. If the value was NULL, the new instance will be empty. An array converts to an object with properties named by keys and corresponding values, with the exception of numeric keys which will be inaccessible unless iterated.

    Object to Array

    And similar issues/quirks present themselves when converting the other way around: (documentation)

    If an object is converted to an array, the result is an array whose elements are the object's properties. The keys are the member variable names, with a few notable exceptions: integer properties are unaccessible; private variables have the class name prepended to the variable name; protected variables have a '*' prepended to the variable name. These prepended values have null bytes on either side. This can result in some unexpected behaviour:

    Basically, objects with numeric properties can be cast to an array, and you can iterate it, but the keys are inaccessible (directly). It's a known quirk. You can get around it by either using json_decode($string, true); to convert to an array right off the bat, or use a secondary loop to "reconstruct" the array:

    $reconstructed = [];
    foreach ((array) $obj as $k => $v) {
        $reconstructed[$k] = $v;
    }
    

    Whether this is a bug or a feature is unclear. When I first encountered this behaviour, I called it a bug. Given that it's documented and a known quirk, I'd now say it's neither. It's not really a bug because it's known, understood and documented, but it's hardly a feature. It's just one of those messy quirks that most languages have.

    You'll have to work around it, live with it, avoid it, and deal with it. Given that there's been many bugreports on the PHP mailing lists about this, and it's added to the documentation, it's probably something that is unlikely to get fixed any time soon.