Sammaye
Sammaye

Reputation: 43884

PHP Return by Reference Clarification

I have an example script here with a return by reference magic __get:

class a{

    public $_attributes = array();

    function &__get($k){
        if(isset($this->_attributes[$k])){
            return $this->_attributes[$k];
        }else{
            return null;
        }
    }

    function __set($k, $v){
        $this->_attributes[$k] = $v;
    }
}


$a = new a();
$a->username = "sam";
var_dump($a->username);
$u = $a->username;
$u = $u.'dddd';
var_dump($a->username);
var_dump($u);

The idea of returning by reference from my __get here is so I can do stuff like:

    $this->user->ins[session_id()] = array(
        "key"=>$_SESSION['server_key'],
        "ip"=>$_SERVER['REMOTE_ADDR'],
        "agent"=>$_SERVER['HTTP_USER_AGENT'],
        "last_request"=>$_SERVER['REQUEST_URI'],
        "last_active"=>new MongoDate(),
    );

Since I cannot normally due to PHP using a copy of the original array. However When I pull say "username" into a new variable ($u) I do not want it to pass a reference of its original parent.

The script above prints out:

string(3) "sam" string(3) "sam" string(7) "samdddd"

Which is awesome becasue it is not passing $username as reference back to $u and it works like I want it to.

Now time for the question: Is this a good approach? Is it expected behaviour in PHP to do this?

I have been reading the page for referencing but it's a bit patchy, however it does mention that to tell PHP that $u should be a reference I must also use the reference symbol when pulling out the variable (as can be seen here: http://php.net/manual/en/language.references.return.php).

So is this expected behaviour and can I rely on it in PHP or is there something terrible I'm not seeing?

Thanks

Upvotes: 0

Views: 106

Answers (2)

Matthew
Matthew

Reputation: 48284

Instead of returning an array by reference, just return an ArrayObject.

class Foo
{
  private $data;

  public function __construct()
  {
    $this->data = new ArrayObject();
  }

  public function __get($key)
  {
    return $this->data;
  }
}

$foo = new Foo();
$foo->data['bar'] = 42;
var_dump($foo->data);

Output:

object(ArrayObject)#2 (1) {
  ["storage":"ArrayObject":private]=>
  array(1) {
    ["bar"]=>
    int(42)
  }
}

Unfortunately PHP ArrayObjects cannot be used directly with PHP array functions, but I would prefer the above over always returning __get by reference.

You can do something similar for scalars if you box them in an object that implements __toString(). And yes, there are flaws with this as well, but I would always discourage using __get by reference.

Upvotes: 0

Alex
Alex

Reputation: 6470

Now time for the question: Is this a good approach? Is it expected behaviour in PHP to do this?

This is a bad (odd) approach. Simply manipulate the object, this is more common practice. The way you have it is tricky and can mislead you during development.

If you decide to continue with your reference approach, you need to make sure you received the value by reference. See sample below:

$a = new a();
// returning by reference is not enough, you need to receive by ref as well
$u =& $a->username;

Upvotes: 1

Related Questions