1

I have an object (Two) which holds an object (One) and an array:

class One {
    public $a;
}

class Two {
    public $object;
    public $array;

    public function __construct() {
        $this->object = new One();
        $this->array = [];
    }

    function getObject() {
        return $this->object;
    }

    function getArray() {
        return $this->array;
    }
}

Why I can manipulate the returned object, but cannot manipulate the returned array:

$two = new Two();
$two->getObject()->a = 'a';
$two->getArray()[] = 'b'; // Does not work!
$two->array[] = 'c';

var_dump($two);

Result (b is missing in the array):

//    class test\Two (2) {
//      protected $object =>
//        class test\One (1) { public $a => string(1) "a" }
//      protected $array => array(1) { [0] => string(1) "c" }
//    }

What makes the difference, as I think there's returned a copy of the reference to the array itself, but not to its elements.

Thanks for your explanation! ;D

User Rebo
  • 3,056
  • 25
  • 30

3 Answers3

2

By default, passing or returning an array makes a copy. You need to return a reference.

    function &getArray() {
        return $this->array;
    }

BTW, you need to declare $array as public so you can access $two->array outside the class.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Thanks for your reply, I already knew that I have to give back a reference, thus I didn't understand what makes return an array different from an object. ;D (Also changed $array to public Thx) – User Rebo Apr 09 '20 at 08:03
1

The reference-like behavior of passing/returning objects results from what variable of type object really holds. The object itself doesn't exist in any variable - only in some space in memory, and what you're passing is really a link/identifier (or simplified pointer) that allows you to make calls to the object's methods and (public) properties (a sort of a middleman). By default objects (which are not really objects, but their representatives) are passed the same way as the array or any other variable - by value (I'm skipping some under the hood optimizations like array's copy on write for example).

Hence the difference in behavior between reassigning object variable and variable passed by reference - the latter will change memory that reference (and its original variable) is pointing to, the former will overwrite "link" to the object, while other identifiers of this object will still hold the same value.

Objects can be passed by reference too, but again as it's not really an object, so you cannot really do anything with it except make calls or break the link itself - this time for both referer and reference variable.

shudder
  • 2,076
  • 2
  • 20
  • 21
0

You need to return the array as reference in your Two class

class One {
    public $a;
}

class Two {
    protected $object;
    protected $array;

    public function __construct() {
        $this->object = new One();
        $this->array = [];
    }

    function getObject() {
        return $this->object;
    }

    function &getArray() { // Here you return as reference
        return $this->array;
    }
}
Felix Lebel
  • 563
  • 10
  • 23