phparrayscasting

Casting an Array with Numeric Keys as an Object


I was poking around PHPs casting mechanism, and ran into an odd case when casting an array as an object

$o = (object) array('1'=>'/foo/bar');   
$o = new stdClass();
var_dump($o);

As I understand it, PHP properties need to be declared with the same rules as PHP variables. That is A valid variable name starts with a letter or underscore, followed by any number of letters, numbers, or underscores. However, the above code produces the following output

object(stdClass)#1 (1) {
  [1]=>
  string(8) "/foo/bar"
}

Where it gets really weird is when you try to access that information in the object.

var_dump($o->1);        // parse error
var_dump($o->{'1'});        // NULL 
var_dump(get_object_vars($o));  //array(0) { }

Is there any way to get at the information that var_dump reports is in the object, or is it just locked up for the rest of the request life cycle? (practical use of this is nil, I'm just curious)


Solution

  • Yes, they are just locked away unless cast back to an array. There are a few little "Gotchas" in PHP, for example in older versions you could define a constant as an array, but then never access its elements. Even now you can define a constant as a resource (e.g., define('MYSQL',mysql_connect());) although this leads to rather unpredictable behavoir and, again, should be avoided.

    Generally, it's best to avoid array-to-object casts if at all possible. If you really need to do this, consider creating a new instance of stdClass and then manually renaming all the variables, for example to _0, _1, etc.

    $a = array('cat','dog','pheasant');
    $o = new stdClass;
    foreach ($a as $k => $v) {
        if (is_numeric($k)) {
            $k = "_{$k}";
        }
        $o->$k = $v;
    }
    

    EDIT: Just did one more quick test on this hypothesis, and yes, they officially "do not exist" in object context; the data is stored, but it's impossible to access, and is therefore the ultimate private member. Here is the test:

    $a = array('one','two','three');
    $o = (object)$a;
    var_dump(property_exists($o, 1), property_exists($o, '1'));
    

    And the output is:

    bool(false)
    bool(false)
    

    EDIT AGAIN: Interesting side-note, the following operation comes back false:

    $a = array('one','two','three','banana' => 'lime');
    $b = array('one','two','banana' => 'lime');
    
    $y = (object)$a;
    $z = (object)$b;
    
    var_dump($y == $z);