I read this from the PHP manual:
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:
class A { private $A; // This will become '\0A\0A' } class B extends A { private $A; // This will become '\0B\0A' public $AA; // This will become 'AA' } var_dump((array) new B());
The above will appear to have two keys named 'AA', although one of them is actually named '\0A\0A'.
I don't quite understand the meaning of those parts with typeface like this.
What's a integer property?
What's the meaning of "These prepended values have null bytes on either side. This can result in some unexpected behaviour"?
and What's the meaning of "?The above will appear to have two keys named 'AA', although one of them is actually named '\0A\0A'"
This refers to properties whose names are string representations of decimal integers. For example:
$o = new stdClass;
$o->{"123"} = 'foo'; // create a new integer property
echo $o->{"123"}, PHP_EOL; // verify it's there
$a = (array)$o; // convert to array
echo $a['123']; // OOPS! E_NOTICE: Undefined offset!
var_dump(array_keys($a)); // even though the key appears to be there!
print_r($a); // the value appears to be there too!
In general, integer properties in PHP are not something you should come anywhere near if you value your sanity.
null
For private
and protected
properties, the generated array keys will contain the non-printable character "\0"
. This might be useful (since that character is not legal for a property name you can use this information to determine the visibility of the properties), but it might also be a nuisance if you don't expect it to be there. Example:
class A {
private $A; // This will become '\0A\0A'
}
class B extends A {
private $A; // This will become '\0B\0A'
public $AA; // This will become 'AA'
}
$a = (array) new B();
// The array appears to have the keys "BA", "AA" and "AA" (twice!)
print_r(array_keys($a));
// But in reality, the 1st and 3rd keys contain NULL bytes:
print_r(array_map('bin2hex', array_keys($a)));
You can extract the visibility information from the array keys like this:
$a = (array) new B();
foreach ($a as $k => $v) {
$parts = explode(chr(0), $k);
if (count($parts) == 1) {
echo 'public $'.$parts[0].PHP_EOL;
}
else if ($parts[1] == "*") {
echo 'protected $'.$parts[2].PHP_EOL;
}
else {
echo 'private '.$parts[1].'::$'.$parts[2].PHP_EOL;
}
}
You may get some insight into the new array keys by using this code.
$x = (array)new B();
foreach ($x as $key => $value) {
echo bin2hex($key), ' = ', $value, PHP_EOL;
}
It shows a hex representation of the key values, from which you can more clearly see what's going on:
00420041 =
4141 =
00410041 =
The array key for the first property (B::A
) is encoded as "\x00B\x00A"
, i.e. chr(0) . 'B' . chr(0) . 'A'
, because its visibility is private to B
.
The second property (B::AA
) is encoded as simply 'AA'
, because its visibility is public.
The third property (A::A
), much like the first, is encoded as "\x00A\x00A"
, because its visibility is private to A
.
I'm not entirely sure what integer properties are though. I wouldn't worry about numerical properties since their usage is negligible and discouraged (which is probably why there's not much mention of this "feature".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With