Casting an Array with Numeric Keys as an Object

后端 未结 4 1246
余生分开走
余生分开走 2020-11-27 07:23

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 =          


        
相关标签:
4条回答
  • 2020-11-27 07:43

    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);
    
    0 讨论(0)
  • 2020-11-27 07:59

    Yes, they are just locked away unless cast back to an array.

    Maybe, the properties are still there and are accessible, just not directly. However, I'm not sure how foreach works internally (it might cast the object to an array) as I have not dived in the source code.

    Example:

    $array = array('one', 'two', 'three', 'four');
    $obj = (object) $array;
    
    foreach ($obj as $key => &$val) {
        print "$key -> $val<br>";
        $val = 'Nhaca';
        var_dump($obj);
    }
    print_r($obj);
    print_r($array);
    

    output:

    0 -> one
    object(stdClass)[1]
      &string 'Nhaca' (length=5)
      string 'two' (length=3)
      string 'three' (length=5)
      string 'four' (length=4)
    1 -> two
    object(stdClass)[1]
      string 'Nhaca' (length=5)
      &string 'Nhaca' (length=5)
      string 'three' (length=5)
      string 'four' (length=4)
    2 -> three
    object(stdClass)[1]
      string 'Nhaca' (length=5)
      string 'Nhaca' (length=5)
      &string 'Nhaca' (length=5)
      string 'four' (length=4)
    3 -> four
    object(stdClass)[1]
      string 'Nhaca' (length=5)
      string 'Nhaca' (length=5)
      string 'Nhaca' (length=5)
      &string 'Nhaca' (length=5)
    stdClass Object ( [0] => Nhaca [1] => Nhaca [2] => Nhaca [3] => Nhaca ) 
    Array ( [0] => one [1] => two [2] => three [3] => four )
    
    0 讨论(0)
  • 2020-11-27 08:05

    It appears that the ArrayObject class can access the properties

    $a = new ArrayObject($obj);
    echo $a[0];
    
    0 讨论(0)
  • 2020-11-27 08:08

    I think you get an error because casting an integer key of an array to an object / subobject will break the naming conventions of PHP varibles.

    Tips:

    • Decide before hands whether you want to have an OBJECT or an ARRAY
    • Be careful with type casting (e.g. (object) array(1=>'string') do not do such things)
    • Use castings for validation and not to convert things
    • Avoid using objects as "fake" arrays
    0 讨论(0)
提交回复
热议问题