Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP class not storing reference

How do I pass a reference to an object constructor, and allow that object to update that reference?

class A{
    private $data;
    function __construct(&$d){
        $this->data = $d;
    }
    function addData(){
        $this->data["extra"]="stuff";
    }
}

// Somewhere else
$arr = array("seed"=>"data");
$obj = new A($arr);
$obj->addData();

// I want $arr to contain ["seed"=>"data", "extra"=>"stuff"]
// Instead it only contains ["seed"=>"data"]
like image 956
Dave Avatar asked Apr 05 '13 20:04

Dave


3 Answers

You must store it everywhere as a reference.

function __construct (&$d) {
    $this->data = &$d; // the & here
}
like image 181
bwoebi Avatar answered Oct 06 '22 21:10

bwoebi


This would do what you are asking for:

class Test {

    private $storage;

    public function __construct(array &$storage)
    {
        $this->storage = &$storage;
    }

    public function fn()
    {
        $this->storage[0] *= 10;
    }
}

$storage = [1];

$a = new Test($storage);
$b = new Test($storage);

$a->fn();
print_r($a); // $storage[0] is 10
print_r($b); // $storage[0] is 10

$b->fn();
print_r($a); // $storage[0] is 100
print_r($b); // $storage[0] is 100

Alternative 1

Instead of using an array, you can also use an ArrayObject, ArrayIterator or SplFixedArray. Since those are objects, they will be passed by reference. All of these implement ArrayAccess so you can access them via square brackets, e.g.

$arrayObject = new ArrayObject;
$arrayObject['foo'] = 'bar';
echo $arrayObject['foo']; // prints 'bar'

Alternative 2

Instead of using a generic type, use a dedicated type. Find out what you are storing in that array. Is it a Config? A Registry? A UnitOfWork? Find out what it really is. Then make it an object and give it an API reflecting the responsibilities. Then inject that object and access it through that API.

See this paper by Martin Fowler to some guidance on When To Make A Type

like image 39
Gordon Avatar answered Oct 06 '22 20:10

Gordon


You'll have to tell PHP to assign a reference also to the private member data like this:

$this->data = &$d;

Depending on the context, you may not want to use references to external arrays, and it might be better to have that array inside an object that handles it.

Aslo notice that the constructor is called __construct not __construction.

like image 30
Shoe Avatar answered Oct 06 '22 20:10

Shoe