简体   繁体   中英

PHP's assignment by reference is not working as expected

Why the following

class AClass
{
    public function __construct ()
    {
        $this->prop = "Hello";
    }
    public function &get ()
    {
        return $this->prop;
    }
    protected $prop;
}

function func (&$ref)
{
    $ref = &$ref->get();
}

$value = new AClass();
func($value);
var_dump( $value );

outputs

object(AClass)#2 (1) {
  ["prop":protected]=>
  string(5) "Hello"
}

Shouldn't the $value variable become a reference to $prop and be of type string instead of staying of type AClass ?

http://ideone.com/g1hTNV

Consider this piece of code (It's the same as your code, just without everything else):

$value = new stdClass;
$ref = &$value;
$var = "Hello";
$ref = &$var; // this is where you write $ref = &$ref->get();
var_dump($value);

This gives as expected an empty object and not string(5) Hello .

Why?

We're in line 4 overwriting the reference to $value with a reference to $var .

$ref now holds a reference to $var ; the value of $value remains unaffected .

What we're not doing

  • We don't assign the value of $var to $value .
  • We don't assign to $value a reference to $var .

Conclusion

Assigning references to a variable via another referencing variable is just not possible in PHP.

bwoebi is totally right about how PHP references work. Without a dereference operator it would become impossible to know exactly what you mean when using pointers, so PHP has used another approach. This does not, however, mean that what you want is impossible, you just can't do it all inside a function:

class AClass
{
    public function __construct ()
    {
        $this->prop = "Hello";
    }
    public function &get()
    {
        return $this->prop;
    }
    public $prop;
}

function &func($ref)
{
    return $ref->get();
}

$root = new AClass();
$value = &func( $root );
var_dump( $value );
  // string(5) "Hello"
$value = "World";
var_dump( $root->get() );
  // string(5) "World"

http://codepad.org/gU6pfzUO

You should remove the ampersand in your func function. Then it will return you the string.

function func (&$ref)
{
    $ref = $ref->get();
}

Just change protected into public for the sake of testing.

$value = new AClass();
$myValue = &$value->get();

var_dump($myValue );
var_dump($value->prop);
$value->prop = 'test';
var_dump($value->prop);
var_dump($myValue );

Output :

 string 'Hello' (length=5)
 string 'Hello' (length=5)
 string 'test' (length=4)
 string 'test' (length=4)

incase you think that function is necessary you can use global variable.

what you want can be acheived by this-

 <?php
class AClass
{
    public function __construct ()
    {
        $this->prop = "Hello";
    }
    public function &get ()
    {
        return $this->prop;
    }
    protected $prop;
}

function func (&$ref)
{
   $ref= $ref->get();

}

$value = new AClass();
func($value);
print_r( $value );
 ?>
class AClass
{
    public function __construct ()
    {
        $this->prop = "Hello";
    }
    public function &get ()
    {
        return $this->prop;
    }
    protected $prop;
}

function func (&$ref)
{
    $ref = $ref->get(); // You don't need the ampersand here
}

$value = new AClass();
func($value);
var_dump( $value ); // outputs: string(5) "Hello"

Your function func() needs to return a value and then it needs to assign to a variable what func() returned. See modified code below:

function func (&$ref) {
    $ref = &$ref->get();
    return $ref;
}

$value = new AClass();
$new_value = func($value);
var_dump( $new_value );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM