引用的解释
在线手册:中文 英文
PHP手册

引用不是什么

如前所述,引用不是指针。这意味着下面的结构不会产生预期的效果:

<?php
function foo(&$var)
{
    
$var =& $GLOBALS["baz"];
}
foo($bar);
?>

这将使 foo 函数中的 $var 变量在函数调用时和 $bar 绑定在一起,但接着又被重新绑定到了 $GLOBALS["baz"] 上面。不可能通过引用机制将 $bar 在函数调用范围内绑定到别的变量上面,因为在函数 foo 中并没有变量 $bar(它被表示为 $var,但是 $var 只有变量内容而没有调用符号表中的名字到值的绑定)。可以使用引用返回来引用被函数选择的变量。


引用的解释
在线手册:中文 英文
PHP手册
PHP手册 - N: 引用不是什么

用户评论:

shuimuqingshu at gmail dot com (13-Mar-2012 10:57)

i think the code below can tell the difference between PHP reference and C pointer:

In PHP:
<?php
    $a
= 0;
   
$b = &a;
    echo
$a; //0
   
unset($b); // unset $b
   
echo $a; //0 it's OK
?>

In C:
#include <stdio.h>
int main(int argc, char const *argv[]) {
    int a = 0;
    int* b = &a;
 
    printf("%i\n", a); //0
    free(b);              // free b
    printf("%i\n", a); //get error: *** error for object 0x7fff6350da08: pointer being freed was not allocated
}

briank at kappacs dot com (25-Jan-2011 10:38)

I think the terminology is tripping people up when it comes to assigning objects.

Try thinking of binding and references like this:

<?php
# Code:
$a = 5; $b =& $a; $c = new stdClass(); $d = $c;

# Behind the scenes symbol table and values:
$global_names = array(
'a' => array('binding' => 0),
'b' => array('binding' => 0),
'c' => array('binding' => 1),
'd' => array('binding' => 2),
);
$values = array(
0 => array('type' => 'scalar', 'value' => 5),
1 => array('type' => 'objId', 'value' => 0),
2 => array('type' => 'objId', 'value' => 0)
);
?>

$a is bound to (or references, or is a reference to) the value at index 0 (scalar 5).
$b is bound to the same thing as $a--the value at index 0 (scalar 5).
$c is bound to the value at index 1 (object ID 0).
$d is bound to the value at index 2 (a separate and distinct value also referring to object ID 0).

When the documentation states that you cannot [re-]bind $bar to something else from within the example function foo, it means you can't change what in my pseudo-engine would be $global_names['bar']['binding']. You can only change $values[$names['var']['binding']] (using "$var ="; the same value referenced/bound by $values[$global_names['bar']['binding']) or $names['var']['binding'] (using "$var =&").

Also consider this code:

<?php
$a
= 3; $b =& $a;
function
foo (&$c) { $c = new stdClass(); }
function
bar () { return new stdClass(); }
function &
fum () { return new stdClass(); }
if (!
is_object($a)) { echo "\$a does not initially refer to an object\n"; }
foo($b);
echo
"\$b ", ($a === $b)? "has not": "has", " been re-bound by foo\n";
if (
is_object($a)) { echo "\$a now contains an object identifier\n"; }
$b =& bar();
echo
"\$b ", ($a === $b)? "has not": "has", " been re-bound by bar\n";
$b =& fum();
echo
"\$b ", ($a === $b)? "has not": "has", " been re-bound by fum\n";
?>

which outputs:

$a does not initially refer to an object
$b has not been re-bound by foo
$a now contains an object identifier
$b has not been re-bound by bar
$b has been re-bound by fum

In other words, the value can be changed but the binding does not (except for returning a reference), exactly as stated.

Object identifiers do make object "values" work like pointers (but not to the extent of C/C++, and not like references).

Anonymous (08-Jul-2010 05:25)

I understand this like that:
 The reference in PHP is like creating single pointer at own variable in C/C++ and point at variable ( without pointers arithmetic and we can't get number of variable address in memory).

For example
<?php
$a
= 4;
$b = &$a;
$c = &$b;
echo
"$a - $b - $c<br>";
// 3 pointers ( a , b , c) point at memory location where  stored value of number is 4.
$c = 5;
echo
"$a - $b - $c<br>";
// all variables equals 5;
unset($a);
$c = 6;
echo
"$a - $b - $c<br>";
//$a is not exist but it was only pointer ( not real part of memory) so we have to way to get value or change it
?>
----
When we want create some "pointer of pointer" in PHP i can't do that because it's impossible in PHP. We need pointer to another pointer to change the place that the pointer refers to. In your exaple you just change value of variable in function. ( no operation of pointers )

russrobinson at tectite dot com (03-May-2010 10:22)

The example shown is correct for scalars.

However, in PHP5 the example does not cover objects, which behave the opposite of the way this documentation indicates.

It is my view that object references in PHP5 are exactly like pointers in C++.

This example code illustrates my point:
<?php
class Dog
{
  var
$Name;
  function
Dog($name)
  {
   
$this->Name = $name;
  }
  function
GetName()
  {
    return (
$this->Name);
  }
};

$bar = new Dog("Spot");
function
foo(&$var)
{
   
$var = new Dog("Gypsy");
}
foo($bar);
echo
"<p>".$bar->GetName();
echo
"<p>"."If that said 'Gypsy', then object references are really pointers";
?>

And the output is:

****
Gypsy

If that said 'Gypsy', then object references are really pointers
****

Therefore, corrected documentation should read (or similar):

"
Unless $bar is an object, there's no way to bind $bar in the calling scope to something else using the reference mechanism since $bar is not available in the function foo (it is represented by $var, but $var has only variable contents and not name-to-value binding in the calling symbol table).

If $bar is an object, then you can change $bar in the calling scope using the reference mechanism inside a function.
"

However, note that when I said:

"It is my view that object references in PHP5 are exactly like pointers in C++."

The "exactly like" part is misleading...

To clarify:

I don't mean PHP5 object references support pointer arithmetic or they contain memory addresses.

I mean that, in PHP5, when you pass object variables to functions they *behave* exactly like pointers to objects do in the same situation when writing in C++ (with the exception of the C++ features that just don't exist in PHP, such as pointer arithmetic).

Namely,
1. When you pass the object variable, the formal parameter behaves like a C++ pointer to the object inside the function.
2. When you pass the object variable by reference, the formal parameter behaves like a C++ reference to a pointer to the object inside the function.

The syntax is different between the languages, but the semantics are identical.

reggae dot player at centrum dot cz (29-Nov-2008 03:52)

I have $scriptVar and $_SESSION['sessionVar'] and I want to bind them together using a custom SessionManager class. I want to selectively prefer the content of either var upon the situation - to be able to "link" either $scriptVar to $_SESSION['sessionVar'] (thus override the "content" of $scriptVar with the content of $_SESSION['sessionVar']) or to link $_SESSION['sessionVar'] to $scriptVar (vice versa).

But as somebody mentioned here already, PHP's references aren't really references, so the simplistic way to do this is impossible to use. I came up with the following:
<code>
... class def and other method declarations ...
public static function &linkVar($varName, &$var = null, $overrideSessionValue = false) {
  if ($overrideSessionValue === true) {
    $_SESSION[$varName] =& $var;
  } else {
    return $_SESSION[$varName];
  }
}
... class def and other method declarations continue ...
</code>
Now, when I want to override the Session value, I simply call the function with three params, first being the session var name, second being a reference to the $scriptVar and the third a "true" telling the function to link $_SESSION[$varName] to $var, which links to $scriptVar and therefore to link $_SESSION[$varName] to $scriptVar. When I want to link it the other way, to override $scriptVar's value with $_SESSION[$varName] and link them together, I call the function with only the $varName argument and assign it's output to $scriptVar as a reference. Tested, working... at least under PHP 5.3.

Andrew (04-Sep-2008 06:56)

What References are not: References.

References are opaque things that are like pointers, except A) smarter and B) referring to HLL objects, rather than memory addresses. PHP doesn't have references. PHP has a syntax for creating *aliases* which are multiple names for the same object. PHP has a few pieces of syntax for calling and returning "by reference", which really just means inhibiting copying. At no point in this "references" section of the manual are there any references.

Anonymous (09-Jun-2008 07:52)

The example given in the text:

<?php
function foo(&$var)
{
   
$var =& $GLOBALS["baz"];
}
foo($bar);
?>

illustrates (to my mind anyway) why the = and & should be written together as a new kind of replacement operator and not apart as in C, like  $var = &$GLOBALS["baz"];

Using totally new terminology:

To me the result of this function is not surprising because the =& means 'change the "destination" of $var from wherever it was to the same as the destination of $GLOBALS["baz"]. Well it 'was' the actual parameter $bar, but now it will be the global at "baz".

If you simply remove the & in the the replacement, it will place the value of $GLOBALS["baz'] into the destination of $var, which is $bar (unless $bar was already a reference, then the value goes into that destination.)

To summarize, =, replaces the 'destination's value; =&, changes the destination.

Anonymous (11-May-2008 05:52)

<?php
function foo(&$var)
{
   
$var =& $GLOBALS["baz"];
}
foo($bar);
?>

As the example bellow, which just say out the reference is  equal to the pointer of variables as c.
See the $var as the pointer, firstly it point to the $bar, then as we use "=&" assign it, it change the pointer itself(not content) and point to the $GLOBALS["baz"].In this flow, the $bar change neighter its ponter nor the content.
This is just the concept in C, isn't it?

frank (21-Jan-2008 10:46)

A little warning: my function my_make_vars()  (see other post) has a side-effect, of course...

$a=array('x'=>1,'y'=>2);

$x0=&$a['x'];

my_make_vars($a);

# $x0  now is not any more a reference to  $a['x'] !!!

$x1=&$a['x'];  # (but $x1 is, because done after the my_make_vars($a);)
$x=4; print $a['x'].' '; #  ->4
print $x0.' '.$x1;   # -> 1 4

Stevel (03-Feb-2007 04:30)

The manual states: "There's no way to bind $bar in the calling scope to something else using the reference mechanism"

This is actually incorrect. It is possible to bind $bar to another object. The given example doesn't work for obvious reasons: $var is redeclared as an alias for $GLOBALS["baz"], instead of an alias for $bar.

You should use an ordinary assignment to assign another object to the same variable. This works because variables containing objects actually contain a reference to that object, and the reference is copied to $var, and therefore is copied to $bar as well.

When using primitive values, such as integers or strings, the values itself are copied. In the example (when excluding the ampersand from the assignment), suppose that $GLOBALS['baz'] contains the value 3, after calling foo($bar), $bar will contain the integer 3, but they won't point to the same memory space.

The correct sentence would be thus:
"There's no way make $bar in the calling scope an alias for something else using the reference mechanism"

Tee Cee (20-Aug-2006 01:59)

You can think of references as pointers, if you translate a=b into "*a = *b" and a =& b into "a=b".

Let's translate to C:

<?PHP
const int c_1 = 1, c_2 = 2;
int * a = &c_1;
int * b = &c_2;

void foo (int * var)
{
   var =
a;
}
?>

Here, it's obvious that calling foo(b) won't change the value of a, because var is a copy of b. You also have to be careful: order does matter. I could draw a diagram, but I won't.

<?php
$b
=1; $d=2;
$a =& $b;
$c =& $d;
// now a=b=1; c=d=2;
$b =& $c;
// now a=1, b=c=d=2;
?>

It's also important to treat =& as its own operator, though you can stick spaces in the middle. The & does not bind to the variable, as shown by
<?php
$a
= (&$b); // parse error
?>

jagatpreet (30-Jan-2006 07:27)

In response to the example by mdiricks.

Extending the example given by mdiricks, the following code provides an explains the concept of re-referencing that is involved in making a call to function foo with the prototype foo(& var):

<!-- C re-referenced -->
<?

$a = 'eh';
$b = & $a;// $b == 'eh'
$c = & $b;// $c == 'eh'
$d = 'meh';

echo "\$a = $a\n";
echo "\$b = $b\n";
echo "\$c = $c\n";
echo "\$d = $d\n";

$c = & $d ;// $c == 'meh'
echo "\n";

echo "\$a = $a\n";
echo "\$b = $b\n";
echo "\$c = $c\n";
echo "\$d = $d\n";

?>

<!-- Value of c changed -->
<?

$a = 'eh';
$b = & $a;// $b == 'eh'
$c = & $b;// $c == 'eh'
$d = 'meh';

echo "\$a = $a\n";
echo "\$b = $b\n";
echo "\$c = $c\n";
echo "\$d = $d\n";

$c = 'meh' ;// $c == 'meh'. And also, $a = $b == 'meh'
echo "\n";

echo "\$a = $a\n";
echo "\$b = $b\n";
echo "\$c = $c\n";
echo "\$d = $d\n";

?>

This results in the following o/p:
<!-- C re-referenced -->
$a = eh
$b = eh
$c = eh
$d = meh

$a = eh
$b = eh
$c = meh
$d = meh

<!-- Value of c changed -->
$a = eh
$b = eh
$c = eh
$d = meh

$a = meh
$b = meh
$c = meh
$d = meh

DanielSan88 (28-Oct-2005 04:10)

I can see why there is a big debate on this. I'm hoping this will clarify it a little.

In PHP, as far as I can understand, when you assign a variable in the first place,
that variable is a refrence to the value that the variable contains.

<?php

$var
= "String"; // Creates the string "String" somewhere in memory.
echo $var;

/* When the echo function is called, it pulls the value of $var out of memory from wherever PHP decided to put it.
PHP then ships this value off to your standard output. */

?>

Anyway, when you create a reference to the variable $var,
it doesn't reference the variable's name, but rather its contents.

For example:

<?php

$var2
= & $var;
echo
$var2;
/* Calling this echo does ecactly the same thing as the echo in the code snippet above this one.
Whether you echo $var or $var2, the same string in memory is sent to your standard output. */

?>

In the same sense of an array, $var and $var2 are like keys to the same value. The value being the string in memory.

When you call a function that uses a reference, the reference is not less than the variable given as the argument, or anything more than it.
It is that same variable except with a different name.

mdirks at gulfstreamcoach dot com (21-Oct-2005 04:40)

Here's a thought to settle the whole (are/aren't) debacle...

References are *like* pointers, but are not *identical to* pointers. The best comparison I could give is that references are "scope-limited pointers". You can change the value of one variable by changing the other as long as it is in the same scope. Once you set outside that scope (i.e. calling a function), references cease to act the same as pointers.

Example 1:
$a = 'eh';
$b = & $a;// $b == 'eh'
$c = & $b;// $c == 'eh'
$a = 'meh';// $c == 'meh'

... changing a's value will change c's value. This is where references are like pointers in C/C++

Example 2:
$GLOBALS["b"] = 'b_val';
$c = 'c_val';

function foo (&$var)
{
   $var =& $GLOBALS["b"]; //affects only 'var' copy
}

$GLOBALS["b"] = & $a; // $GLOBALS["b"] == 'a_val'
foo($c); // the value of c will remain 'c_val'

... It might help to think of it in a different way. A calling the function by reference mimics the following behavior:
$var = & $c;

... so when you if you execute this line in foo():
$var =& $GLOBALS["b"];
, you are just re-referencing var from what it was "referenced to" at the function call to a new reference.

This is where references are *not* like pointers in C/C++ as the value of c is not changed as it would be if a similiar function that implemented pointers were used.

I hope this clears up the confusion.

mstasak at access4less dot net (11-Jul-2005 03:18)

Note references in array elements behave very much the same as pointers.  The following seems to defy the simple definition of array assignment as copy-by-value:

unset($a);
unset($b);

$a[1]=1;
$a[2]=&$a[1];

$b=$a;
$b[2]=7;

print_r($a);
Array
(
    [1] => 7
    [2] => 7
)
print_r($b);
Array
(
    [1] => 7
    [2] => 7
)

- so array assignment is a very shallow copy-by-value, which preserves reference associations in any array elements.  Oddly, I believe PHP lacks a deep array-copy-by-value function.

fzamperini_at_tin.it (16-Jun-2005 10:35)

References are not like pointers.

If you try the example above in C/C++ you will find that after calling foo(var) you can get or set the value of $GLOBALS["baz"] by reading or writing variable 'var' (I didn't actually try it, but I vaguely remember it works this way).
In PHP this is also true if you do:

<?PHP
    $var
=& $GLOBALS["baz"];
?>

but *IT IS NOT* if you use a function to do that, in spite of
- using a reference as a parameter (function foo(&$var)) and
- assigning it a reference to the variable you want to bind ($var =& $GLOBALS["baz"]) inside the function

I tried this:

<?PHP
$GLOBALS
["baz"] = 'globals_baz';
$bar = 'bar';

function
foo (&$var)
{
   
$var =& $GLOBALS["baz"];
}

// Before 'binding' $bar to $GLOBALS["baz"] using a function
echo '$GLOBALS[baz]: ' . $GLOBALS["baz"] . "<BR>\n";    // Output is 'globals_baz'
echo "\$bar: $bar <BR>\n";    // Output is 'bar'

foo($bar);

// After (what you may expected to be a) binding you should see that $bar is the same as $GLOBALS[baz]:
echo "\$bar: $bar <BR>\n"; // it didn't work: output is still 'bar' (not 'globals_baz')

// And setting $bar should set $GLOBALS[baz]:
$bar = 'bar';
echo
'$GLOBALS[baz]: ' . $GLOBALS["baz"] . "<BR>\n"; // it didn't work, too: output is still 'globals_baz' (not 'bar')
?>

If you change the calling of foo($bar) with $bar =& $GLOBALS["baz"]; it all works as expected.
So the assertion, "references are not like pointers," might be a bit confusing but it is fair.

ansonyumo at email dot com (28-Feb-2004 09:47)

The assertion,  "references are not like pointers," is a bit confusing.

In the example, the author shows how assigning a reference to a formal parameter that is also a reference does not affect the value of the actual parameter. This is exactly how pointers behave in C. The only difference is that, in PHP, you don't have to dereference the pointer to get at the value.

-+-+-
int bar = 99;

void foo(int* a)
{
    a = &bar;
}

int main()
{
   int baz = 1;
   foo(&baz);
   printf("%d\n", baz);
   return 0;
}
-+-+-

The output will be 1, because foo does not assign a value to the dereferenced formal parameter. Instead, it reassigns the formal parameter within foo's scope.

Alternatively,
-+-+-
int bar = 99;

void foo(int* a)
{
    *a = bar;
}

int main()
{
   int baz = 1;
   foo(&baz);
   printf("%d\n", baz);
   return 0;
}
-+-+-

The output will be 9, because foo dereferenced the formal parameter before assignment.

So, while there are differences in syntax, PHP references really are very much like pointers in C.

I would agree that PHP references are very different from Java references, as Java does not have any mechanism to assign a value to a reference in such a way that it modifies the actual parameter's value.

schultz __at__ widescreen __dot__ ch (26-Jan-2004 03:57)

A not so simple Workaround...but still doable...have fun

class My{
    var $value;
   
    function get1(&$ref){
        $ref[] =& $this;
    }
   
    function get2(&$ref){
        $ref =& $this;
    }
   
    function get3(&$ref){
        $ref = $this;
    }
}

$m = new My();

$m->value = 'foo';
$m->get1($ref=array());
$m1 =& $ref[0];
$m1->value = 'bar';
echo "\n".'Works but is ugly...';
echo "\n".' m:'. get_class($m) . '->value = '. $m->value;
echo "\n".' m1:'. get_class($m1) . '->value = '. $m1->value;

echo "\n".'Does not work because references are not pointers...';
$m->value = 'foo';
$m->get2($m2);
$m2->value = 'bar';
echo "\n".' m:'. get_class($m) . '->value = '. $m->value;
echo "\n".' m2:'. get_class($m2) . '->value = '. $m2->value;

$m->value = 'foo';
$m->get3($m3);
$m3->value = 'bar';
echo "\n".'Does not work becuase it is set to a copy';
echo "\n".' m:'. get_class($m) . '->value = '.$m->value;
echo "\n".' m3:'. get_class($m3) . '->value = '. $m3->value;

christian at kno dot at (13-Oct-2001 02:04)

As said above references are not pointers.

Following example shows a difference between pointers and references.

This Code
<?
    $b = 1;
    $a =& $b;

    print("<pre>");
    print("\$a === \$b: ".(($a === $b) ? "ok" : "failed")."\n");
    print("unsetting \$a...\n");
    unset($a);
    print("now \$a is ".(isset($a) ? "set" : "unset")." and \$b is ".(isset($b) ? "set" : "unset")."\n");
    print("</pre>");

    $b = 1;
    $a =& $b;

    print("<pre>");
    print("\$a === \$b: ".(($a === $b) ? "ok" : "failed")."\n");
    print("unsetting \$b...\n");
    unset($b);
    print("now \$a is ".(isset($a) ? "set" : "unset")." and \$b is ".(isset($b) ? "set" : "unset")."\n");
    print("</pre>");
?>

will produce this output:
---------
$a === $b: ok
unsetting $a...
now $a is unset and $b is set

$a === $b: ok
unsetting $b...
now $a is set and $b is unset
---------

So you see that $a and $b are identical ($a === $b -> true), but if one of both is unset, the other is not effected.