-1

I'm having this code here and no matter what I do all the items in the array are the same when I do a var_dump(). I don't know why I can't loose the reference and what to do about it.

Here is a code simplification replicating the same behaviour

class Numbr {
    public $value = NULL;

    function __construct(int $value) {
        $this->value = $value;
    }

    public function multiply(int $multiplier) {
        $this->value *= $multiplier;
    }
}

class Test {
    public $operations = [];

    function __construct($values) {
        $operations = [];
        foreach($values AS $value) $operations[] = new Numbr($value);
        $this->operations = $operations;
    }

    public function simulation() {
        $ops = $this->operations;

        //Here I make 4 copies of $ops that I want to end up being different
        $op1 = $this->transformation($ops, 2);
        $op2 = $this->transformation($ops, -2);
        $op3 = $this->transformation($ops, -1);
        $op4 = $this->transformation($ops, 4);

        $this->operations = [$op1, $op2, $op3, $op4];
    }

    public function transformation(array $ops, int $value) {
        $output = [];
        foreach($ops AS $N) {
            $N->multiply($value);
            $output[] = $N;
        }
        return $output;
    }
}

$Test = new Test([1,2,3,4]);
$Test->simulation();
var_dump($Test)
Frank Malenfant
  • 126
  • 1
  • 11
  • What kind of poorly designed framework is this? Like, what's the source so some of us can possibly sift through the docs. – Adam Feb 21 '18 at 21:45
  • I don't see anywhere where you are _copying list of objects_? – AbraCadaver Feb 21 '18 at 21:50
  • @Adam It's not a framework, it's some code to translate CNC files between two formats. If you can't wrap yout mind around this I can build a simpler simulation of the same thing. There is an object containing a list, but I have to rewrite this list in 5 different versions depending of different points of reference so the original list has to become a list of lists. – Frank Malenfant Feb 21 '18 at 21:53
  • It's not elegant I know, but it's the only way I can fit as many options in the very limited destination file format. – Frank Malenfant Feb 21 '18 at 21:54
  • @AbraCadaver $GO->operations = $ops; ($ops is a list of objects) – Frank Malenfant Feb 21 '18 at 21:55
  • What does the `GpcOp` class look like? ... and ... do all 5 dumps match your expectation for $op1 or $op5? – Lee Kowalkowski Feb 21 '18 at 22:02
  • @AbraCadaver `$ops` is an array, `clone` is for objects. Arrays are automatically copied when you assign them, unless you use a reference variable. – Barmar Feb 21 '18 at 22:14
  • @LeeKowalkowski Here, I replaced the code by a simplification replicating the same results – Frank Malenfant Feb 21 '18 at 22:14
  • @AbraCadaver I totally agree, however this code (I changed it for a much simplet version) makes all 4 arrays exactly the same. – Frank Malenfant Feb 21 '18 at 22:15
  • You're saying `$ops` is an array of objects, so in the new code: `$output[] = clone $N;` – AbraCadaver Feb 21 '18 at 22:19
  • @AbraCadaver SInce $N is in a loop inside a function, how could this $N possibly be attached to an instance of itself anywhere else? – Frank Malenfant Feb 21 '18 at 22:21
  • @AbraCanada By the way, you are right. Although it seems very weird to me, I have to clone $N in order to detach it from whatever reference it still has. Many thanks! – Frank Malenfant Feb 21 '18 at 22:25
  • @FrankMalenfant Objects are passed by reference, they're not copied. So you're modifying the objects in place. – Barmar Feb 21 '18 at 22:25
  • Yes, https://3v4l.org/lCYpk – AbraCadaver Feb 21 '18 at 22:28

2 Answers2

0

Thanks to @AbraCadaver here is the solution

public function transformation(array $ops, int $value) {
        $output = [];
        foreach($ops AS $N) {
            $P = clone($N); //But why?
            $P->multiply($value);
            $output[] = clone($P);
        }
        return $output;
    }
Frank Malenfant
  • 126
  • 1
  • 11
0

The output from var_dump explains.

object(Test)#1 (1) {
  ["operations"]=>
  array(4) {
    [0]=>
    array(4) {
      [0]=>
      object(Numbr)#2 (1) {
        ["value"]=>
        int(16)
      }
      [1]=>
      object(Numbr)#3 (1) {
        ["value"]=>
        int(32)
      }
      [2]=>
      object(Numbr)#4 (1) {
        ["value"]=>
        int(48)
      }
      [3]=>
      object(Numbr)#5 (1) {
        ["value"]=>
        int(64)
      }
    }
    [1]=>
    array(4) {
      [0]=>
      object(Numbr)#2 (1) {
        ["value"]=>
        int(16)
      }
      [1]=>
      object(Numbr)#3 (1) {
        ["value"]=>
        int(32)
      }
      [2]=>
      object(Numbr)#4 (1) {
        ["value"]=>
        int(48)
      }
      [3]=>
      object(Numbr)#5 (1) {
        ["value"]=>
        int(64)
      }
    }
    [2]=>
    array(4) {
      [0]=>
      object(Numbr)#2 (1) {
        ["value"]=>
        int(16)
      }
      [1]=>
      object(Numbr)#3 (1) {
        ["value"]=>
        int(32)
      }
      [2]=>
      object(Numbr)#4 (1) {
        ["value"]=>
        int(48)
      }
      [3]=>
      object(Numbr)#5 (1) {
        ["value"]=>
        int(64)
      }
    }
    [3]=>
    array(4) {
      [0]=>
      object(Numbr)#2 (1) {
        ["value"]=>
        int(16)
      }
      [1]=>
      object(Numbr)#3 (1) {
        ["value"]=>
        int(32)
      }
      [2]=>
      object(Numbr)#4 (1) {
        ["value"]=>
        int(48)
      }
      [3]=>
      object(Numbr)#5 (1) {
        ["value"]=>
        int(64)
      }
    }
  }
}

All objects are numbered. Each array contains the same 4 objects, [object(Numbr)#2, object(Numbr)#3, object(Numbr)#4, object(Numbr)#5]

When you create a new array, you perhaps want to clone these objects and not reuse them, or just $output[] = $N->value if it's just for output.

Lee Kowalkowski
  • 11,591
  • 3
  • 40
  • 46