-3

I've tried to print the number 200 from this array but I don't know how to do it with the (object) cast.

$x= [(object)["items"=>[1=>100,2=>200]]];
ccarpan
  • 31
  • 4

1 Answers1

-2

You shouldn't cast an array to an object blindly, because it's not safe. PHP explicitly warns against this in the manual.

An array converts to an object with properties named by keys and corresponding values, with the exception of numeric keys which will be inaccessible unless iterated.

PHP Manual: Type Juggling

Which means that any numeric keys in an array that's cast to an object will become inaccessible. In this particular case, the only key in the array being cast happens to be a string, which means that $x->items[2] will give the expected result.

So for example, $x = (object) [1=>100,2=>200] will result in $x[2] and $x["2"] to always be null despite var_dump($x) showing otherwise. Which might be very peculiar to the casual observer.

As such, if what you want is to cast arrays to object safely you could use this approach instead.

function recursiveArrayToObject(Array $arr, stdClass $obj = null) {
    if (!$obj) {
        $obj = new stdClass;
    }
    foreach($arr as $key => $value) {
        if (is_array($value)) {
            $obj->$key = recursiveArrayToObject($value);
        } else {
            $obj->$key = $value;
        }
    }
    return $obj;
}

$x = ["items"=>[1=>100,2=>200]];
$xObj = recursiveArrayToObject($x);
var_dump($xObj);

This gives you...

object(stdClass)#1 (1) {
  ["items"]=>
  object(stdClass)#2 (2) {
    ["1"]=>
    int(100)
    ["2"]=>
    int(200)
  }
}

So now $xObj->items->{"2"} will give you 200, as expected.

If you want the safe, non-recursive version...

function arrayToObject(Array $arr, stdClass $obj = null) {
    if (!$obj) {
        $obj = new stdClass;
    }
    foreach($arr as $key => $value) {
        $obj->$key = $value;
    }
    return $obj;
}

$x = ["items"=>[1=>100,2=>200]];
$xObj = arrayToObject($x);
var_dump($xObj, $xObj->items[2]);

Output...

object(stdClass)#1 (1) {
  ["items"]=>
  array(2) {
    [1]=>
    int(100)
    [2]=>
    int(200)
  }
}
int(200)
Sherif
  • 11,786
  • 3
  • 32
  • 57
  • 1
    Sure it can. `items` is the only property of the resulting object, so it's not a problem. – AbraCadaver Sep 22 '16 at 18:36
  • @AbraCadaver That might be the case, but my assumption was that they meant to cast the entire array as an object. I could have assumed wrong. – Sherif Sep 22 '16 at 18:45
  • In any case, it's *never* safe to blindly cast arrays to objects because of this integer key problem you get inaccessible object properties. Still a note worthy thing even if it doesn't apply in this one very particular case with this one very particular set of data. – Sherif Sep 22 '16 at 18:46
  • **I continue to stand by my answer despite the downvote and closed vote. Arrays should not be cast to objects like that as they cannot be safely relied upon.** – Sherif Sep 22 '16 at 18:52
  • 3
    Wasn't me. It's a pretty decent answer except it doesn't apply to `$x= [(object)["items"=>[1=>100,2=>200]]];` – AbraCadaver Sep 22 '16 at 18:53
  • @AbraCadaver but it *generally* applies to casting *any* array to an object. Doing so with an `(object)` cast is unsafe behavior you should *always* avoid. My answer is more general even if it doesn't apply to the specific case, but I digress... It's a closed vote regardless. I just wanted to reiterate that I stand by my answer. Wasn't directed at you. – Sherif Sep 22 '16 at 18:57
  • 1
    I haven't downvoted you either, but I don't think I would call that statement from the manual an explicit warning. It's just telling you how it works; it doesn't really say you shouldn't do it. – Don't Panic Sep 22 '16 at 19:03
  • @Don'tPanic Actually, it does say **exactly** why you shouldn't do it. If you blindly assume that casting an array to an object will work every time and aren't aware that numeric keys in an array will not cast properly unless you iterate the keys, then the result is as such. Which is why answer generally applies to any case. – Sherif Sep 22 '16 at 19:08
  • I guess we'll have to agree to disagree. (Still haven't downvoted you, though.) – Don't Panic Sep 22 '16 at 19:15
  • @Don'tPanic I wasn't directing that to anyone in particular. Again, just reiterating that ***I will continue to stand by my answer even if all of StackOverflow down votes it into oblivion*** :-) – Sherif Sep 22 '16 at 19:17