Object and Array Casting

Nov 29, 2011

A few days ago, I posted about some interesting behavior when casting arrays to objects. I would like to take a look at some other interesting behavior. Lets start be creating a basic class Test with three properties each with a different visibility.

class Test {
  private $foo;
  protected $bar;
  public $bat;
  public function __construct() {
    $this->foo = "lorem";
    $this->bar = "dolor";
    $this->bat = "amit";
  }
}

Now create a new instance of the class and cast it to an array.

$test = new Test();
print_r((array)$test);

The result is as follows:
Array
(
    [Testfoo] => lorem
    [*bar] => dolor
    [bat] => amit
)

On the surface it appears as if the private property had the class name prepended and the and the protected property had an astrick prepended. Now what happens if we cast this array back to an object?
$test_object = new Test();
$test_array = (array)$test_object;
var_dump((object)$test_array);

Results in:

object(stdClass)#2 (3) {
  ["foo":"Test":private]=>
  string(5) "lorem"
  ["bar":protected]=>
  string(5) "dolor"
  ["bat"]=>
  string(4) "amit"
}

How did PHP know the Testfoo key and the *bar key were private and protected? After all, doing the following does not work:

$test_array = array("Testfoo" => "lorem", "*bar" => "dolor", "bat" => "amit");
var_dump((object)$test_array);

It turns out, PHP stores meta information with the keys in the form of null bytes. Thus

$test_array = array(
  "\x00Test\x00foo" => "lorem",
  "\x00*\x00bar" => "dolor",
  "bat" => "amit"
  );
var_dump((object)$test_array);

Results in the object we expect.
object(stdClass)#2 (3) {
  ["foo":"Test":private]=>
  string(5) "lorem"
  ["bar":protected]=>
  string(5) "dolor"
  ["bat"]=>
  string(4) "amit"
}