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

引用传递

可以将一个变量通过引用传递给函数,这样该函数就可以修改其参数的值。语法如下:

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

$a=5;
foo($a);
// $a is 6 here
?>
注意在函数调用时没有引用符号——只有函数定义中有。光是函数定义就足够使参数通过引用来正确传递了。在最近版本的 PHP 中如果把 & 用在 foo(&$a); 中会得到一条警告说“Call-time pass-by-reference”已经过时了。

以下内容可以通过引用传递:

任何其它表达式都不能通过引用传递,结果未定义。例如下面引用传递的例子是无效的:

<?php
function bar() // Note the missing &
{
    
$a 5;
    return 
$a;
}
foo(bar()); // 自 PHP 5.0.5 起导致致命错误
foo($a 5// 表达式,不是变量
foo(5// 导致致命错误
?>
这些条件是 PHP 4.0.4 以及以后版本有的。


引用的解释
在线手册:中文 英文
PHP手册
PHP手册 - N: 引用传递

用户评论:

bkfake-php at yahoo dot com (15-Mar-2012 01:49)

It should be noted that
call_user_func_array('function', array(&$a));
is effectively a call-time pass by reference

it should also be noted that it does not throw any error or warning in any version of php.    PHP 5.4 continues to not throw a warning.    Also, as of PHP 5.4, the var will not be passed by reference.

jocelyn dot heuze at gmail dot com (19-Oct-2011 06:12)

Please note that you can't pass NULL to a function by reference, unless it's as a default value.

<?php

function foo(&$a = NULL) {
    if (
$a === NULL) {
        echo
"NULL\n";
    } else {
        echo
"$a\n";
    }
}

foo(); // "NULL"
foo(5); // "5"
foo(NULL); // Produces an error

?>

4d88 dot results at gmail dot com (04-May-2011 04:15)

This is the way how we use pointer to access variable inside the class.

<?php
class talker{

    private
$data = 'Hi';

    public function &
get(){
        return
$this->data;
    }
   
    public function
out(){
        echo
$this->data;
    }   

}

$aa = new talker();
$d = &$aa->get();

$aa->out();
$d = 'How';
$aa->out();
$d = 'Are';
$aa->out();
$d = 'You';
$aa->out();
?>

the output is "HiHowAreYou"

northhero at gmail dot com (24-Aug-2010 08:25)

Someone mentioned that passing reference doesn't work as  expected from within call_user_func(). For example:

<?php
$string
= 'string';
function
change(&$str) {
   
$str = 'str';
}
call_user_func('change', $string);
echo
$string;
?>

output:
string               //not as expected 'str'

Here we could assume call_user_func as below

<?php
function call_user_funct($func, $param) {
   
$func($param);
}
?>

As calling $func() inside call_user_funct, here is change(), the variable $param is copied to a third variable then the temp variable is passed to the $func. So $str only hold the reference of the temp variable inside change().
Of course , if we pass  &$string directly to call_user_func we could always get the result as expected (str).

northhero at gmail dot com (24-Aug-2010 03:02)

Passing variable reference to function instead of declaring the function parameter type to reference also could get the result as expected.

<?php
$string
= 'string';
function
change($str) {
   
$str = 'str';
}
change(&$string);
echo
$string;
?>

yeild

str

PhoneixSegovia at GOOGLEMAILSERVER dot com (06-Jul-2010 04:05)

If you call it without nothing (no variable, no constant) then a new variable is created with null or the default parameter.
If a null parameter is passed, then this (null) variable is used, even with a default value specified.

A simple example:
<?php

print '<pre>';

function
foo(&$a=5){
   
$a +=2;
    print
"\nIn foo => $a";
}

function
bar(&$a){
   
$a += 2;
    print
"\nIn bar => $a";
}

$a;
$b;
print
"Initial:\n";
var_dump($a, $b);

foo();
bar();

print
"\nAfter void call:\n";
var_dump($a, $b);

foo($a);
bar($b);

print
"\nAfter passed:\n";
var_dump($a, $b);

print
'</pre>';
?>

Output is:
"Initial:
NULL
NULL

In foo => 7
In bar => 2
After void call:
NULL
NULL

In foo => 2
In bar => 2
After passed:
int(2)
int(2)"

Note that null is equal to 0 in a mathematical expresion.

rvw at cosninix dot com (08-Feb-2010 10:13)

Watch out that passing an uninitialised variable to a function will create the variable and will NOT give a NOTICE-undefined variable:

<?php
function ifnull(&$v,$default) {
   if (isset(
$v)) return $v;
   return
$default;
}

$p=array();
$p['apple']=3;
echo
ifnull($p['apple'],4);   -> 3
echo ifnull($p['pear'],5);    -> 5  No "undefined index" here.
if (isset(
$p['pear'])) echo "pear is set"; else echo "pear not set"; -> not set
if (array_key_exists('pear',$p)) echo "pear exists"; else echo "pear doesn't exist";  -> pear exists!
?>

Tom (21-Jul-2009 12:54)

Still puzzled with references?

See this code:
<?php
function a(&$a, &$b) { $a =& $b; }
$a = 1;
$b = 2;
a($a, $b);
$b = 3;
print
$a;
?>

If you expect the output to be 3, you are wrong. $a remains unchanged and the output is 1. The reference was NOT assigned to $a.

Now let's try this one:
<?php
function a(&$a, &$b) { $a = $b; }
$a = 1;
$b = 2;
a($a, $b);
$b = 3;
print
$a;
?>

If you thought that now the output would be 3, you are wrong again. It's 2.

However this:
<?php
$a
= 1;
$b = 2;
$a =& $b;
$b = 3;
print
$a;
?>
Actually outputs 3.

But how about Objects? Objects, you might think, are always passed by reference. So this should work!

Well, let's check it out:
<?php
function a($a, $b) { $a = $b; }
$a = new StdClass;
$a->i = 1;
$b = new StdClass;
$b->i = 2;
a($a, $b);
$b->i = 3;
print
$a->i;
?>
Outputs 1! So obviously you are wrong again.

What's the reason? Simple! The first (and the last) code example above translates to this fragment:
<?php
$a
= 1;
$b = 2;
$a1 =& $a;
$b1 =& $b;
$a1 =& $b1;
$b = 3;
print
$a;
?>

Now THAT makes it clear, right?

If you are referencing a reference you are NOT making the original pointer change it's destination like in Java or C#, because it is not dereferenced automatically. Instead you are overwriting the local pointer. You will make $a1 point to $b, which has no influence on the original $a.

This is different from all you might expect if you have been programming in other OO-languages before, so you should keep that in mind.

me at khurram dot nl (12-Sep-2008 03:55)

in php 5.2.0 for classes

$obj1  =  $obj2;
is equal to
$obj1  =  &$obj2;"

<?php

class z {
    public
$var = '';
    }
 
$a = new z();
$b   =&  $a;
$c  = $a;

$a->var = null;

var_dump($a);
print
'<br>';
var_dump($b);
print
'<br>';
var_dump($c);
print
'<br><br>';

$a->var = 2;

var_dump($a);
print
'<br>';
var_dump($b);
print
'<br>';
var_dump($c);
print
'<br><br>';

?>

mehea (20-May-2008 01:04)

New in PHP5:  assign default value to
pass-by-reference paramter.

I didn't believe it even when I read
http://devzone.zend.com/article/1714-Whats-New-in-PHP-5

Then I tried this:

<?php
function my_func(&$arg = 22) {
    if (
$arg == 22) {
        print
'$arg is '. $arg;
    }
}
my_func();
?>

Guess what? It works, even tho' not clear about what $arg is actually referencing!

Chuckie (28-Oct-2007 04:33)

If you intend to pass a copy of an object to a function, then you should use 'clone' to create a copy explicity.  In PHP5, objects appear to always be passed by reference (unlike PHP4), but this is not strictly true.

The way I think of it is that if you use '=&' (or you explicitly pass to a function by reference) the variable behaves like a C++ reference, except that you can re-assign the reference to something else (which is not possible in C++).

When you use '=' with an object, it is more like you are dealing with a pointer (if you think in this way, the '->' access element through pointer operator has the same behaviour in C++).

<?php

class z {
    public
$var = '';
    }
  
function
f(&$obj1, $obj2, $obj3, $obj4) {
 
$obj1->var = null;
 
$obj2->var = null;
 
$obj3 = new z();
 
$obj3->var = null;
 
$obj4 = clone $obj4;
 
$obj4->var = null;
  }
$a = new z();
$b = new z();
$c = new z();
$d = new z();
f($a, $b, $c, $d);

var_dump($a); // object(z)#1 (1) { ["var"] => NULL }
var_dump($b); // object(z)#2 (1) { ["var"] => NULL }
var_dump($c); // object(z)#3 (1) { ["var"] => string(0) "" }
var_dump($d); // object(z)#4 (1) { ["var"] => string(0) "" }

?>

Stephen
08-Jul-2007 04:54
jcastromail at yahoo dot es stated:
****
in php 5.2.0 for classes

$obj1  =  $obj2;
is equal to
$obj1  =  &$obj2;"
****

However, that is not completely true. While both = and =& will make a variable refer to the same object as the variable being assigned to it, the explicit reference assignment (=&) will keep the two variables joined to each other, whereas the assignment reference (=) will make the assigned variable an independent pointer to the object. An example should make this clearer:

<?php

class z {
    public
$var = '';
    }
  
$a = new z();
$b   =&  $a;
$c  = $a;

$a->var = null;

var_dump($a);
print
'<br>';
var_dump($b);
print
'<br>';
var_dump($c);
print
'<br><br>';

$a = 2;

var_dump($a);
print
'<br>';
var_dump($b);
print
'<br>';
var_dump($c);
print
'<br><br>';

?>

This outputs:

object(z)#1 (1) { ["var"]=> NULL }
object(z)#1 (1) { ["var"]=> NULL }
object(z)#1 (1) { ["var"]=> NULL }

int(2)
int(2)
object(z)#1 (1) { ["var"]=> NULL }

So although all 3 variables reflect changes in the object, if you reassign one of the variables that were previously joined by reference to a different value, BOTH of those variables will adopt the new value.

Perhaps this is because =& statements join the 2 variable names in the symbol table, whereas = statements applied to objects simply create a new independent entry in the symbol table that simply points to the same location as other entries. I don't know for sure - I don't think this behavior is documented in the PHP manual, so perhaps somebody with more knowledge of PHP's internals can clarify what is going on.

sony-santos at bol dot com dot br (27-Jul-2007 09:06)

Just another workaround for default values to parameters by ref in response to mogmios, bobbykjack, andrzej, fdelizy, petruzanautico, Train Boy, and php community.

<?php
# php 4.3.10

# note there's no & in function declaration:
function f($a = array('default value')) {
 
$a[0] .= " processed<br/>";
  echo
$a[0];
}

f(); # default value processed

$b = 'foo';

f(array(&$b)); # foo processed (note the & here)

echo $b; # foo processed
?>

doron (09-Jul-2007 02:06)

I found that

f1(&$par=0);

behaves differently in 5.2.4 thatn in 5.0.4
in 5.2.4 the par is assined to zero AFTER function call
and thus, par is allways ZERO !
in 5.0.4 in is INITIALIZED to zero, BEFORE function call!

petruzanautico at yahoo dot com dot ar (25-Sep-2006 09:30)

Actually there is a way to give a default value to a reference argument, if you need it badly.
It fires a warning, but you can prefix the function call with an @.
Of course, you cannot pass literals by reference.

<?php
function byref( &$ref )
{
  if( !isset(
$ref ) )
   
$ref = "default value";
  print
$ref; // default or given value? who knows!
}

$hi = "some value ";
byref( $hi ); // works fine
@byref(); // missing argument warning, but works
byref( "hey!" ); // this will raise a fatal error
?>

fdelizy at unfreeze dot net (12-Aug-2006 05:32)

Some have noticed that reference parameters can not be assigned a default value. It's actually wrong, they can be assigned a value as the other variables, but can't have a "default reference value", for instance this code won't compile :

<?php
function use_reference( $someParam, &$param =& $POST )
{
 ...
}
?>

But this one will work :

<?php
function use_reference( $someParam, &$param = null )
?>

So here is a workaround to have a default value for reference parameters :

<?php
$array1
= array ( 'test', 'test2' );

function
AddTo( $key, $val, &$array = null)
{
    if (
$array == null )
    {
     
$array =& $_POST;
    }

   
$array[ $key ] = $val ;
}

AddTo( "indirect test", "test", $array1 );
AddTo( "indirect POST test", "test" );

echo
"Array 1 " ;
print_r ( $array1);

echo
"_POST ";
print_r( $_POST );

?>

And this scripts output is :

Array 1 Array
(
    [0] => test
    [1] => test2
    [indirect test] => test
)
_POST Array
(
    [indirect POST test] => test
)

Of course that means you can only assign default reference to globals or super globals variables.

Have fun

rmarscher (15-Sep-2005 11:42)

Not sure if this is obvious to everyone, but if you pass an object by reference into a function and then set that variable to the reference of a new object, the initial variable outside the function is still pointing to the original object. 

It became obvious to me why this is the case when I made a little diagram of what's actually happening in the system's memory, but before that when I was just looking at the code, it took me a while of testing before I realized what was going on.

Here's an example (I haven't tried in PHP5, but I would guess it works the same):
<?php
class Foo {}
class
Bar {}

function &
createBar()
{
  return new
Bar;
}

function
setBar(& $obj)
{
  echo
get_class($obj) . "\n";
 
$obj = & createBar();
  echo
get_class($obj) . "\n";
}

$test = new Foo;
setBar($test);
echo
get_class($test);
?>

Outputs:
foo
bar
foo

pillepop2003 at yahoo dot de (13-Feb-2005 04:08)

PHP has a strange behavior when passing a part of an array by reference, that does not yet exist.

<?php
   
function func(&$a)
    {
       
// void();
   
}
   
   
$a['one'] =1;
   
func($a['two']);
?>   

var_dump($a) returns

    array(2) {
        ["one"]=>
        int(1)
        ["two"]=>
        NULL
    }

...which seems to be not intentional!

obscvresovl at NOSPAM dot hotmail dot com (26-Dec-2004 06:51)

Just a simple note...

<?php

$num
= 1;

function
blah(&$var)
{
   
$var++;
}

blah($num);

echo
$num; #2

?>

<?php

$num
= 1;

function
blah()
{
   
$var =& $GLOBALS["num"];
   
$var++;
}

blah();

echo
$num; #2

?>

Both codes do the same thing! The second code "explains" how passage of parameters by reference works.

jbr at diasparsoftware dot com (28-Sep-2004 05:46)

Strangely enough, I had to put "&" on the call site, but not on the function parameter list, in order to get this to work. Here is the code:

<?php
class TestRunner {
    var
$passed;
    var
$failed;
    var
$tests;
   
    function
TestRunner() {
       
$this->passed = 0;
       
$this->failed = 0;
       
$this->tests = array();
    }

    function
addTest($test) {
       
$this->tests[] = $test;
    }

    function
signalFailed() {
       
$this->failed++;
    }
       
    function
runTests() {
        foreach (
$this->tests as $i => $eachName) {
           
call_user_func($eachName, &$this);
        }
    }
       
    function
report() {
       
?>
        <p><?= count($this->tests) ?> run, <?= $this->passed ?> passed, <?= $this->failed ?> failed</p>       
        <?php
   
}
}

function
testNullStringIsEmpty($testRunner) {
   
$testRunner->signalFailed();
}

$testRunner = new TestRunner;
$testRunner->addTest("testNullStringIsEmpty");
$testRunner->runTests();
$testRunner->report();
?>

Notice that testNullStringIsEmpty() does not declare that it wants a reference to a test runner, whereas on the function call site, we pass in &$this. When I run this, I get "1 run, 0 passed, 1 failed"; but when I switch the location of the & to the function parameter list, I get "1 run, 0 passed, 0 failed". This is the exact opposite to what the manual claims. I have no idea why that is.

Sergio Santana: ssantana at tlaloc dot imta dot mx (10-Sep-2004 04:25)

Sometimes we need functions for building or modifying arrays whose elements are to be references to other variables (arrays or objects for instance). In this example, I wrote two functions 'tst' and 'tst1' that perform this task. Note how the functions are written, and how they are used.

<?php
function tst(&$arr, $r) {
 
// The argument '$arr' is declared to be passed by reference,
  // but '$r' is not;
  // however, in the function's body, we use a reference to
  // the '$r' argument
 
 
array_push($arr, &$r);
 
// Alternatively, this also could be $arr[] = &$r (in this case)
}
 
$arr0 = array();          // an empty array
$arr1 = array(1,2,3);   // the array to be referenced in $arr0

// Note how we call the function:
tst($arr0, &$arr1); // We are passing a reference to '$arr1' in the call !

print_r($arr0); // Contains just the reference to $arr1

array_push($arr0, 5); // we add another element to $arr0
array_push($arr1, 18); // we add another element to $arr1 as well

print_r($arr1); 
print_r($arr0); // Changes in $arr1 are reflected in $arr0

// -----------------------------------------
// A simpler way to do this:

function tst1(&$arr, &$r) {
 
// Both arguments '$arr' and '$r" are declared to be passed by
  // reference,
  // again, in the function's body, we use a reference to
  // the '$r' argument
 
 
array_push($arr, &$r);
 
// Alternatively, this also could be $arr[] = &$r (in this case)
}

 
$arr0 = array();          // an empty array
$arr1 = array(1,2,3);   // the array to be referenced in $arr0

// Note how we call the function:
tst1($arr0, $arr1); // 'tst1' understands '$r' is a reference to '$arr1'

echo "-------- 2nd. alternative ------------ <br>\n";

print_r($arr0); // Contains just the reference to $arr1

array_push($arr0, 5); // we add another element to $arr0
array_push($arr1, 18);

print_r($arr1); 
print_r($arr0); // Changes in $arr1 are reflected in $arr0

// This outputs:
// X-Powered-By: PHP/4.1.2
// Content-type: text/html
//
// Array
// (
//     [0] => Array
//         (
//             [0] => 1
//             [1] => 2
//             [2] => 3
//         )
//
// )
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 18
// )
// Array
// (
//     [0] => Array
//         (
//             [0] => 1
//             [1] => 2
//             [2] => 3
//             [3] => 18
//         )
//
//     [1] => 5
// )
// -------- 2nd. alternative ------------
// Array
// (
//     [0] => Array
//         (
//             [0] => 1
//             [1] => 2
//             [2] => 3
//         )
//
// )
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 18
// )
// Array
// (
//     [0] => Array
//         (
//             [0] => 1
//             [1] => 2
//             [2] => 3
//             [3] => 18
//         )
//
//     [1] => 5
// )
?>

In both cases we get the same result.

I hope this is somehow useful

Sergio.

ben at mekhaye dot net (01-Sep-2004 10:27)

Passing arrays by reference doesn't work as I expected from within call_user_func.

I had:

  <?php
  $arr
= Array();
 
call_user_func(Array("ClassName","functionName"), $param1, $param2, $arr);
 
print_r($arr);

  class
ClassName {

     
functionName($param1, $param2, &$arr) {
       
$arr[0] = "apple";
       
$arr[1] = "banana";
       
print_r($arr);
      }
  }
 
?>

I expected the output to be like:

  Array ( [0] => "apple" [1] => "banana" )
  Array ( [0] => "apple" [1] => "banana" )

but instead it was only:

  Array ( [0] => "apple" [1] => "banana" )

However, when I changed the function call to plain old:

  <?php
  $arr
= Array();
 
ClassName::functionName($param1,$param2,$arr);
 
print_r($arr);
 
?>

Output was the expected:

  Array ( [0] => "apple" [1] => "banana" )
  Array ( [0] => "apple" [1] => "banana" )

php at meKILLTHIStatoandthisols dot org (09-Jun-2004 08:33)

Ever been in a situation where you have to write:

  <?php
    $t
= 1 ;
   
$x =& $t ;
 
?>

or

  <?php
    $t
= 1 ;
   
f( $t ) ;
 
?>

because you cannot pass constants by value. The function

  <?php
   
function& pclone( $v ) {
      return(
$v ) ;
    }
 
?>

lets you get ridd of the temporary variable. You can write:

  <?php
    $x
=& pclone( 1 ) ;
 
?>

or

  <?php
    f
( pclone( 1 ) ) ;
 
?>

Alternatively you can use the other alternative ;-)

blistwon-php at designfridge dot com (18-Jan-2004 02:33)

One thing to note about passing by reference. If you plan on assigning the reference to a new variable in your function, you must use the reference operator in the function declaration as well as in the assignment. (The same holds true for classes.)

<?php
function f1(&$num) {
   
$num++;
}
function
f2(&$num) {
   
$num1 = $num;
   
$num1++;
}
function
f3(&$num) {
   
$num1 = &$num;
   
$num1++;
}

$myNum = 0;
print(
"Declare myNum: " . $myNum . "<br />\n");
f1($myNum);
print(
"Pass myNum as ref 1: " . $myNum . "<br />\n");
f2($myNum);
print(
"Pass myNum as ref 2: " . $myNum . "<br />\n");
f3($myNum);
print(
"Pass myNum as ref 3: " . $myNum . "<br />\n");
?>

-------------------------------------------------------
OUTPUT
-------------------------------------------------------
 Declare myNum: 0
 Pass myNum as ref 1: 1
 Pass myNum as ref 2: 1
 Pass myNum as ref 3: 2
-------------------------------------------------------

Hope this helps people trying to detangle any problems with pass-by-ref.