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
Passagem por referência
Você pode passar variáveis para funções por referência, então a função poderá modificar seus argumentos. A sintaxe é a seguinte:
<?php
function foo (&$var)
{
$var++;
}
$a=5;
foo ($a);
// $a é 6 aqui
?>
As coisas a seguir podem ser passadas por referência:
- Variáveis. Exemplo: foo($a)
- Instrução new. Exemplo foo(new foobar())
-
Outra referência, retornada de uma função. Exemplo:
Veja explicações sobre isso em retorno por referência.<?php
function &bar()
{
$a = 5;
return $a;
}
foo(bar());
?>
Nenhuma outra expressão poderá ser passada por referência, com resultados indefinidos. Por exemplo, o exemplo seguinte de passagem por referência é inválido:
<?php
function bar() // Note a falta do &
{
$a = 5;
return $a;
}
foo(bar());
foo($a = 5); // Expressão, não é variável
foo(5); // Constante, não é variável
?>
rmarscher ¶
7 years ago
diabolos @t gmail dot com ¶
11 months ago
<?php
/*
This function internally swaps the contents between
two simple variables using 'passing by reference'.
Some programming languages have such a swap function
built in, but PHP seems to lack such a function. So,
one was created to fill the need. It only handles
simple, single variables, not arrays, but it is
still a very handy tool to have.
No value is actually returned by this function, but
the contents of the indicated variables will be
exchanged (swapped) after the call.
*/
// ------------------------------------------
// Demo call of the swap(...) function below.
$a = 123.456;
$b = 'abcDEF';
print "<pre>Define:\na = $a\nb = '$b'</pre>";
swap($a,$b);
print "<pre>After swap(a,b):\na = '$a'\nb = $b</pre>";
// -------------------------------
function swap (&$arg1, &$arg2)
{
// Swap contents of indicated variables.
$w=$arg1; $arg1=$arg2; $arg2=$w;
}
?>
Tom ¶
3 years ago
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.
jocelyn dot heuze at gmail dot com ¶
1 year ago
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
?>
Chuckie ¶
5 years ago
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.
4d88 dot results at gmail dot com ¶
2 years ago
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"
lubaev dot ka at gmail dot com ¶
17 days ago
<?php
error_reporting(E_ALL);
function f( &$arg ) {
echo $arg;
}
// 1.
f( function(){return 1000;});
// Fatal error: Only variables can be passed by reference in ...
// 2.
f( 1000 );
// Fatal error: Only variables can be passed by reference in ...
// 3.
f( $a = 1000);
// Strict Standards: Only variables should be passed by reference in ...
// 1000
northhero at gmail dot com ¶
2 years ago
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 ¶
2 years ago
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 ¶
2 years ago
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 ¶
3 years ago
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!
?>
me at khurram dot nl ¶
4 years ago
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>';
?>
sony-santos at bol dot com dot br ¶
5 years ago
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 ¶
5 years ago
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 ¶
6 years ago
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 ¶
6 years ago
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
pillepop2003 at yahoo dot de ¶
8 years ago
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 ¶
8 years ago
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 ¶
8 years ago
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 ¶
8 years ago
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 ¶
8 years ago
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 ¶
9 years ago
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 ;-)
David R ¶
1 year ago
One thing I reckon is simple but pretty cool is that if you take a reference from a reference, they both point to the same thing original variable (as you would hopefully expect).
This means you can pass in a variable (by reference), and then make a reference from that, you can make changes to the original variable later.
<?php
class DelayedChange {
private $changeTarget;
public function prepareForChange(&$target) {
// Save a reference to the variable we want to change
$this->changeTarget = &$target;
}
public function change($value) {
// Assign a new value
$this->changeTarget = $value;
}
}
$testVar = "value 1";
$delayedChange = new DelayedChange();
$delayedChange->prepareForChange($testVar);
echo ($testVar."<br>\n"); // outputs "value 1"
$delayedChange->change("value 2");
echo ($testVar."<br>\n"); // outputs "value 2"
?>
(naturally, this only works if you make $changeTarget a reference - if you just write "$this->changeTarget = $target" then it copies $testVar's value instead of taking a new reference to it.)
sagiwagi at live dot com ¶
1 year ago
It should be noted that documentation above does not fully show
how extract a value from the following code:
<?php
function foo(&$var)
{
$var++;
}
function &bar()
{
$a = 5;
return $a;
}
foo(bar());
?>
The following will work:
<?php
function foo(&$var)
{
$var++;
return $var;
}
function &bar()
{
$a = 5;
return $a;
}
echo foo(bar());
?>
mehea ¶
5 years ago
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!
blistwon-php at designfridge dot com ¶
9 years ago
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.
