Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 anyway to get at the 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)

like image 625
Alan Storm Avatar asked Dec 08 '09 21:12

Alan Storm


2 Answers

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);
like image 57
Dereleased Avatar answered Oct 21 '22 16:10

Dereleased


It appears that the ArrayObject class can access the properties

$a = new ArrayObject($obj);
echo $a[0];
like image 39
rrehbein Avatar answered Oct 21 '22 14:10

rrehbein