Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a integer property and what's the meaning of '\0A\0A'?

Tags:

php

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'"

like image 481
Yishu Fang Avatar asked Jan 27 '13 12:01

Yishu Fang


2 Answers

Integer properties

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.

Prepended values surrounded by 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;
    }
}
like image 199
Jon Avatar answered Oct 20 '22 07:10

Jon


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".

like image 4
Ja͢ck Avatar answered Oct 20 '22 07:10

Ja͢ck