0

I've inherited a codebase where I found something a refined and "boiled" version of which is below

$json = '[ {"id": 1, "val":"apple"}, {"id": 2, "val":"mango"} ]';

$data = json_decode($json);
$arr = [];
foreach($data as $d){
    $m->id  = $d->id;
    $m->val = $d->val;
    $arr[] = $m;
}

print_r($arr);

Result

Array
(
    [0] => stdClass Object
        (
            [id] => 2
            [val] => mango
        )

    [1] => stdClass Object
        (
            [id] => 2
            [val] => mango
        )

)

My question is why would the current iteration have any effect on its predecessor?

PHP version : 7.2

EDIT : Apologies if the problem looks related to json but it isn't, instead in my codebase I have these objects coming from another called function. I have used json_decode merely to illustrate the problem

Vinay
  • 7,442
  • 6
  • 25
  • 48
  • Where does `$m` come from? also, add `, true` to `json_decode()`, `json_decode($json, true)`. – Anuga Sep 12 '20 at 15:44
  • You are adding items to `arr` that is declared empty, not to `data` that is not empty (because it's declared with `json_decode()`) – Vincenzo Manto Sep 12 '20 at 15:45
  • @LawrenceCherone because you __defined__ `$m`. – u_mulder Sep 12 '20 at 15:47
  • Could have just done: https://3v4l.org/K055h – Anuga Sep 12 '20 at 15:47
  • Yes mere json_decode is clean but problem arises when you have an object inside loop, excuse me if the problem looks bit confusing as there is `json_*code` in the codebase rather i have used that just for a reference to create vanilla objects – Vinay Sep 12 '20 at 15:49
  • This also solves it without defining $m: `$m['id'] = $d->id; $m['val'] = $d->val;` – HoldOffHunger Sep 12 '20 at 15:50
  • @u_mulder yeah my bad in php8 its a fatal error *Fatal error: Uncaught Error: Attempt to assign property "id" on null* so just presumed it was left out, didn't think to check php7.. anyways seems like you have answered – Lawrence Cherone Sep 12 '20 at 15:50

1 Answers1

3

$m is defined nowhere explicitly. So when php first mets $m, php creates this variable. And as you have -> notation, php understands that this is object. All other iterations just wotk with the same instance of $m.

Also, with error reporting enabled you would see the warning:

Warning: Creating default object from empty value in

And in php8 you will get a fatal error.

Solution:

foreach($data as $d){
    // explicitly define $m
    $m = new stdClass;
    $m->id  = $d->id;
    $m->val = $d->val;
    $arr[] = $m;
}
u_mulder
  • 54,101
  • 5
  • 48
  • 64
  • Hrm, curious -- then how does it work without defining `$m`?` This works fine: `$m['id'] = $d->id; $m['val'] = $d->val;` Does PHP treat undefined values treated as objects as the same instance and other undefined values as vars of a diff instance? – HoldOffHunger Sep 12 '20 at 15:49
  • Because you create `$m` as an array and each assigning `$arr[] = $m` assigns a copy of this array. Replace with `$arr[] = &$m` and see the OP's situation. – u_mulder Sep 12 '20 at 15:52