引用做什么

PHP 的引用允许用两个变量来指向同一个内容。意思是,当这样做时:

<?php
$a
=& $b;
?>

这意味着 $a$b 指向了同一个变量。

注: $a$b 在这里是完全相同的,这并不是 $a 指向了 $b 或者相反,而是 $a$b 指向了同一个地方。

注: 如果具有引用的数组被拷贝,其值不会解除引用。对于数组传值给函数也是如此。

同样的语法可以用在函数中,它返回引用,以及用在 new 运算符中(PHP 4.0.4 以及以后版本):

<?php
$bar
=& new fooclass();
$foo =& find_var($bar);
?>

注: 不用 & 运算符导致对象生成了一个拷贝。如果在类中用 $this,它将作用于该类当前的实例。没有用 & 的赋值将拷贝这个实例(例如对象)并且 $this 将作用于这个拷贝上,这并不总是想要的结果。由于性能和内存消耗的问题,通常只想工作在一个实例上面。

尽管可以用 @ 运算符来抑制构造函数中的任何错误信息,例如用 @new,但用 &new 语句时这不起效果。这是 Zend 引擎的一个限制并且会导致一个解析错误。

警告

如果在一个函数内部给一个声明为 global 的变量赋于一个引用,该引用只在函数内部可见。可以通过使用 $GLOBALS 数组避免这一点。

例子 21-1. 在函数内引用全局变量

<?php
$var1
= "Example variable";
$var2 = "";

function
global_references($use_globals)
{
    global
$var1, $var2;
    if (!
$use_globals) {
        
$var2 =& $var1; // visible only inside the function
    
} else {
        
$GLOBALS["var2"] =& $var1; // visible also in global context
    
}
}

global_references(false);
echo
"var2 is set to '$var2'\n"; // var2 is set to ''
global_references(true);
echo
"var2 is set to '$var2'\n"; // var2 is set to 'Example variable'
?>
global $var; 当成是 $var =& $GLOBALS['var']; 的简写。从而将其它引用赋给 $var 只改变了本地变量的引用。

注: 如果在 foreach 语句中给一个具有引用的变量赋值,被引用的对象也被改变。

例子 21-2. 引用与 foreach 语句

<?php
$ref
= 0;
$row =& $ref;
foreach (array(
1, 2, 3) as $row) {
    
// do something
}
echo
$ref; // 3 - last element of the iterated array
?>

警告

复杂数组最好拷贝而不是引用。下面的例子不会如期望中那样工作。

例子 21-3. 复杂数组的引用

<?php
$top
= array(
    
'A' => array(),
    
'B' => array(
        
'B_b' => array(),
    ),
);

$top['A']['parent'] = &$top;
$top['B']['parent'] = &$top;
$top['B']['B_b']['data'] = 'test';
print_r($top['A']['parent']['B']['B_b']); // array()
?>

引用做的第二件事是用引用传递变量。这是通过在函数内建立一个本地变量并且该变量在呼叫范围内引用了同一个内容来实现的。例如:

<?php
function foo(&$var)
{
    
$var++;
}

$a=5;
foo($a);
?>

将使 $a 变成 6。这是因为在 foo 函数中变量 $var 指向了和 $a 指向的同一个内容。更多详细解释见引用传递

引用做的第三件事是引用返回


add a note add a note User Contributed Notes
chat~kaptain524 at neverbox dot com
25-Aug-2005 12:15
Example 21-3 says that using references in "complex arrays" may not work as expected.  But I have found a way around it, to get normal reference behavior.

Compare the output of these two scripts:

<?php
for ( $i = 0; $i < 10; $i ++ ) $top[$i] = &$top;
$top['A'] = 'AAAAA'; var_dump( $top );
?>

<?php
$z
= &$top;
for (
$i = 0; $i < 10; $i ++ ) $top[$i] = &$top;
$top['A'] = 'AAAAA'; var_dump( $top );
?>

Running PHP 5.0, the first generates about 157457 lines while the second only generates 2554 lines.  The only difference in the code is setting an initial reference before adding self-references inside the array.  This simple step prevents the array from being duplicated every time another self-reference is added.

I am not sure if the duplication is intentional or if it's a bug in the way references are created, but the docs certainly recognize it.
+CurTis-
23-May-2005 03:15
I know that most everyones' comments are really insightful and many have exceptional PHP code to share, but I just wanted to point out a nice little method for situations where you are not sure what your variables contain exactly.

When developing, and you hit a wall debugging, be sure to echo your variable's contents at various stages of your script, so you can more easily track down where your problem is occurring. This is especially helpful when in a complicated referencing situation (like ladoo at gmx dot at's situation below). Also, be sure to make use of print_r, it is a life-saver!

Take care,
+CurTis-
curtis
23-May-2005 03:13
I know that most everyones' comments are really insightful and many have exceptional PHP code to share, but I just wanted to point out a nice little method for situations where you are not sure what your variables contain exactly.

When developing, and you hit a wall debugging, be sure to echo your variable's contents at various stages of your script, so you can more easily track down where your problem is occurring. This is especially helpful when in a complicated referencing situation (like ladoo at gmx dot at's situation below). Also, be sure to make use of print_r, it is a life-saver!

Take care,
+CurTis-
curtis
23-May-2005 03:12
I know that most everyones' comments are really insightful and many have exceptional PHP code to share, but I just wanted to point out a nice little method for situations where you are not sure what your variables contain exactly.

When developing, and you hit a wall debugging, be sure to echo your variable's contents at various stages of your script, so you can more easily track down where your problem is occurring. This is especially helpful when in a complicated referencing situation (like ladoo at gmx dot at's situation below). Also, be sure to make use of print_r, it is a life-saver!

Take care,
+CurTis-
ladoo at gmx dot at
17-Apr-2005 05:05
I ran into something when using an expanded version of the example of pbaltz at NO_SPAM dot cs dot NO_SPAM dot wisc dot edu below.
This could be somewhat confusing although it is perfectly clear if you have read the manual carfully. It makes the fact that references always point to the content of a variable perfectly clear (at least to me).

<?php
$a
= 1;
$c = 2;
$b =& $a; // $b points to 1
$a =& $c; // $a points now to 2, but $b still to 1;
echo $a, " ", $b;
// Output: 2 1
?>
miqrogroove
21-Mar-2005 05:40
More on references and globals:

String variables are not automatically passed by reference in PHP.  Some other languages, such as Visual Basic, will do that automatically for all variables.  PHP will not.

Consider the case where a function receives a global variable as a parameter and also has the same variable defined locally with the 'global' statement.  Do the parameter and global variable now reference the same memory?

No, they do not!  Passing the global variable into the function as a parameter caused a second variable to be created by default.

Here is an example of this scenario:

<?php

$teststring
="Hello";
one();

function
one(){
   global
$teststring;
  
two($teststring);
   echo
$teststring// The value is "World"
}

function
two($param){
   global
$teststring;
  
$teststring="World";
   echo
$param// The value is "Hello"
  
$param="Clear?";
}

?>

Enjoy
x123 t bestof dsh inter dt net
15-Dec-2004 06:42
It might be worth to note that a reference can be created to an unexisting variable, the reference is then "undefined" (NOT isset()) but when the other variable is created, the reference also gets "isset":

<?= phpversion(),
aa, isset($gg), bb, $a=&$GLOBALS[gg], isset($gg),cc,
isset(
$a),dd, $gg=ee, isset($gg),ff, isset($a),hh, $a
?>

prints

4.2.0RC2aabbccddee1ff1hhee

As I did not find anything about this "feature" in the doc, maybe better don't rely on it.

(but where the heck is this "undefined" reference living while it is not set ?)
php.devel at homelinkcs dot com
16-Nov-2004 07:16
In reply to lars at riisgaardribe dot dk,

When a variable is copied, a reference is used internally until the copy is modified.  Therefore you shouldn't use references at all in your situation as it doesn't save any memory usage and increases the chance of logic bugs, as you discoved.
lars at riisgaardribe dot dk
20-Jul-2004 07:49
A comment to pbaltz at NO_SPAM dot cs dot NO_SPAM dot wisc dot edu:
The following code did not work as I expected either:

while ( $row = mysql_fetch_array( $result ) ) {
  // ... do something ...

  // Now store the array $row in an array containing all rows.

  $result_array[] = &$row; // I dont want to copy - there is a lot of data in $row
}

var_dump ( $result_array ) shows that all stored values now are "false" as this is the last value of $row.
Instead the code should be:

while ( $row = mysql_fetch_array( $result ) ) {
  // ... do something ...

  $result_array[] = &$row;
  unset ( $row ); //breaks the linkage between $row and a line in $result_array
}
Hope this is understandable/usefull
phpmaster a#t cybercow #se=
21-May-2004 01:15
Regarding to what "todd at nemi dot net"  said, that you don't need to add an ampersand on code like this, because you get the same result without it.

function myClass() {
  //...some code... 
  return $this;
}
$myObj =& new myClass()

I just experienced something else. I have a pretty complicated/large class relation ship in one part of our software. And when I didn't enter the ampersand I got a totally different result from my function, an array from a totaly different array.

So my suggestion is that you enter the ampersand so it looks like this.

function &getError()
{
return $this->systemError;
}

$errors = & $connection->getError();
agggka at hotmail dot com
19-Feb-2004 10:49
to jazfresh at hotmail dot com (comments from 17-Feb-2004)
You don't really need array_keys()

<?
function &findMyObjectByName($name)
{
  foreach (
$this->my_array as $key => $obj)
  {
   if (
0 == strcmp($name, $obj->getName()))
   { return (
$my_array[$key]); }
  }
  return (
null); // Not found
}
?>
jazfresh at hotmail dot com
17-Feb-2004 07:39
Say you want to search an array, with the intention of returning a reference to the value (so that the parent function can directly edit the array element). You cannot use "foreach" or "each" in the traditional way, because those functions will make a copies of the object, rather than return references to the original array element.

<?
// This will return a copy of the object, not the original!
function &findMyObjectByName($name) {
  foreach(
$this->my_array as $obj) {
   if(
$obj->getName() == $name) {
       return
$obj;
   }
  }
  return
null; // Not found
}
?>

To avoid this pitfall, use array_keys():

<?
// This will return a reference to the original object.
function &findMyObjectByName($name) {
  foreach(
array_keys($this->my_array) as $key) {
   if(
$this->my_array[$key]->getName() == $name) {
       return
$my_array[$key];
   }
  }
  return
null; // Not found
}
?>
php-doc-21-may-2003 at ryandesign dot com
21-May-2003 09:34
To Jeb in regard to his comment from March 2003, the easier way to handle your situation -- the possibility that the server will have an older version of PHP which doesn't support $_GET -- is to include the following at the top of every page:

if (!isset($_GET)) $_GET =& $GLOBALS['HTTP_GET_VARS'];

Then just use $_GET everywhere as usual.
joachim at lous dot org
11-Apr-2003 06:46
So to make a by-reference setter function, you need to specify reference semantics _both_ in the parameter list _and_ the assignment, like this:

class foo{
   var $bar;
   function setBar(&$newBar){
     $this->bar =& newBar;
   }
}

Forget any of the two '&'s, and $foo->bar will end up being a copy after the call to setBar.
todd at nemi dot net
12-Feb-2002 03:15
tbutzon@imawebdesigner.com Makes an excellent point in his reference examples, however, what you find in practice is that you do not need the & in the function definition to actually assign the reference. It is redundant.

The proper way to return a reference is by using:

function &myClass() {
  //...some code... 
  return $this;
}
$myObj =& new myClass()

...however, this produces the exact same result:

function myClass() {
  //...some code... 
  return $this;
}
$myObj =& new myClass()

Apparently, the Ampersand on the assignment is all that is really needed for a reference to truly be assigned. The Ampersand on the function definition actually does nothing.
pbaltz at NO_SPAM dot cs dot NO_SPAM dot wisc dot edu
01-May-2001 04:02
Just a note for others who may run into this.  When the manual says that references are bound to the same copy of the content, it means exactly that.

So doing something like this,

$a = 1;
$b =& $a;
$b = 2;
print "$a $b";

will print '2 2'.  This can be frustrating to track down if, like me, you are used to Perl where you explicitly dereference refrences.  Since $a and $b both reference the same data, changing either, changes both. 

It may be obvious to others, but if you are familiar with pointers or Perl references the automatic dereferencing can be confusing if you forget about it.