PHP Passing by Reference
In PHP, arguments to a function can be passed by value or passed by reference. By default, values of actual arguments are passed by value to formal arguments which become local variables inside the function. Hence, modification to these variables doesn’t change value of actual argument variable.
When arguments are passed by reference, change in value of formal argument is reflected in actual argument variable because the former is a reference to latter. Thus pass by reference mechanism helps in indirectly manipulating data in global space. It also helps in overcoming the fact that a function can return only one variable.
Pass by Value
In following example, two variables are passed to swap() function. Even though swapping mechanism takes place inside the function it doesn’t change values of variables that were passed
Example
"; $temp=$arg1; $arg1=$arg2; $arg2=$temp; echo "inside function after swapping: arg1=$arg1 arg2=$arg2
"; > $arg1=10; $arg2=20; echo "before calling function : arg1=$arg1 arg2=$arg2
"; swap($arg1, $arg2); echo "after calling function : arg1=$arg1 arg2=$arg2
"; ?>
Output
This example gives following output
before calling function : arg1=10 arg2=20 inside function before swapping: arg1=10 arg2=20 inside function after swapping: arg1=20 arg2=10 after calling function : arg1=10 arg2=20
Pass by reference
In order to receive arguments by reference, variable used formal argument must be prefixed by & symbol. It makes reference to variables used for calling the function. Hence, result of swapping inside function will also be reflected in original variables that were passed
Example
"; $temp=$arg1; $arg1=$arg2; $arg2=$temp; echo "inside function after swapping: arg1=$arg1 arg2=$arg2
"; > $arg1=10; $arg2=20; echo "before calling function : arg1=$arg1 arg2=$arg2
"; swap($arg1, $arg2); echo "after calling function : arg1=$arg1 arg2=$arg2
"; ?>
Output
Result of swapping will be shown as follows
before calling function : arg1=10 arg2=20 inside function before swapping: arg1=10 arg2=20 inside function after swapping: arg1=20 arg2=10 after calling function : arg1=20 arg2=10
In following example, array element are references to individual variables declared before array initialization. If element is modified, value of variable also changes
Example
Output
Values of $a, $b and $c also get incremented
It is also possible to pass by reference an array to a function
Example
$arr=[1,2,3,4,5]; arrfunction($arr); foreach ($arr as $i) echo $i . " "; ?>
Output
Modified array will be displayed as follows
Object and reference
In PHP, objects are passed by references by default. When a reference of object is created, its reference is also sent as argument in the form of $this which is also reference to first object
Example
name; > function setname($name)< $this->name=$name; > > $obj1=new test1(); $obj2=&$obj1; $obj1->setname("Amar"); echo "name: " .$obj2->getname(); ?>
Output
Above code will display following output
Php class passing by reference in
You can pass a variable by reference to a function so the function can modify the variable. The syntax is as follows:
$a = 5 ;
foo ( $a );
// $a is 6 here
?>
Note: There is no reference sign on a function call — only on function definitions. Function definitions alone are enough to correctly pass the argument by reference.
- Variables, i.e. foo($a)
- References returned from functions, i.e.:
No other expressions should be passed by reference, as the result is undefined. For example, the following examples of passing by reference are invalid:
foo ( $a = 5 ); // Expression, not variable
foo ( 5 ); // Produces fatal error
foo (new Foobar ()) // Produces a notice as of PHP 7.0.7
// Notice: Only variables should be passed by reference
?>
User Contributed Notes 18 notes
By removing the ability to include the reference sign on function calls where pass-by-reference is incurred (I.e., function definition uses &), the readability of the code suffers, as one has to look at the function definition to know if the variable being passed is by-ref or not (I.e., potential to be modified). If both function calls and function definitions require the reference sign (I.e., &), readability is improved, and it also lessens the potential of an inadvertent error in the code itself. Going full on fatal error in 5.4.0 now forces everyone to have less readable code. That is, does a function merely use the variable, or potentially modify it. now we have to find the function definition and physically look at it to know, whereas before we would know the intent immediately.
// Here we use the ‘use’ operator to create a variable within the scope of the function. Although it may seem that the newly created variable has something to do with ‘$x’ that is outside the function, we are actually creating a ‘$x’ variable within the function that has nothing to do with the ‘$x’ variable outside the function. We are talking about the same names but different content locations in memory.
$x = 10 ;
(function() use ( $x ) $x = $x * $x ;
var_dump ( $x ); // 100
>)();
var_dump ( $x ); // 10
beware unset() destroys references
$x = ‘x’;
change( $x );
echo $x; // outputs «x» not «q23» —- remove the unset() and output is «q23» not «x»
Within a class, passing array elements by reference which don’t exist are added to the array as null. Compared to a normal function, this changes the behavior of the function from throwing an error to creating a new (null) entry in the referenced array with a new key.
class foo <
public $arr = [ ‘a’ => ‘apple’ , ‘b’ => ‘banana’ ];
public function normalFunction ( $key ) return $this -> arr [ $key ];
>
public function & referenceReturningFunction ( $key ) return $this -> arr [ $key ];
>
>
$bar = new foo ();
$var = $bar -> normalFunction ( ‘beer’ ); //Notice Error. Undefined index beer
$var = & $bar -> referenceReturningFunction ( ‘beer’ ); // No error. The value of $bar is now null
var_dump ( $bar -> arr );
/**
[
«a» => «apple»,
«b» => «banana»,
«beer» => null,
],
*/
?>
This is in no way a «bug» — the framework is performing as designed, but it took careful thought to figure out what was going on. PHP7.3
Parameters passed by references can have default values.
You can find out if a variable was actually passed by using func_num_args():
function refault ( & $ref = ‘Do I have to be calculated?’ ) echo ‘NUM ARGS: ‘ . func_num_args (). «\n» ;
echo «ORI VALUE: < $ref >\n» ;
if( func_num_args () > 0 ) $ref = ‘Yes, expensive to calculate result: ‘ . sleep ( 1 );
else $ref = ‘No.’ ;
echo «NEW VALUE: < $ref >\n» ;
>
$result = ‘Do I have to be calculated?’ ;
refault ( $result );
echo «RESULT: < $result >\n» ;
// NUM ARGS: 1
// ORI VALUE: Do I have to be calculated?
// NEW VALUE: Yes, expensive to calculate result: 0
// RESULT: Yes, expensive to calculate result: 0
refault ();
// NUM ARGS: 0
// ORI VALUE: Do I have to be calculated?
// NEW VALUE: No.
?>
The notes indicate that a function variable reference will receive a deprecated warning in the 5.3 series, however when calling the function via call_user_func the operation aborts without fatal error.
This is not a «bug» since it is not likely worth resolving, however should be noted in this documentation.
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.
*/
print «
Define:\na = $a \nb = ' $b '
» ;
swap ( $a , $b );
print «
After swap(a,b):\na = ' $a '\nb = $b
» ;
function swap (& $arg1 , & $arg2 )
// Swap contents of indicated variables.
$w = $arg1 ; $arg1 = $arg2 ; $arg2 = $w ;
>
For anyone wondering, the copy-on-write behaviour just does the Right Thing™ when an array is passed to a function not by-ref which then passes it through to another function by-ref without writing to it. For example:
function do_sort (array $array ) : array usort ( $array , function ( $a , $b ) return strnatcasecmp ( $a [ ‘name’ ], $b [ ‘name’ ]);
>);
var_dump ( $data );
do_sort ( $data ); // does not affect value of $data
var_dump ( $data );
$data = do_sort ( $data );
var_dump ( $data );
I designed a class that can easily pass references.
#### Problem 1
function problem (& $value )
>
problem ( 1 ); // cannot be passed by reference
#### Problem 2
class problem2
static function __callStatic ( $name , & $arguments ) // cannot take arguments by reference
>
>
?>
My solution 👇
class Reference
function __construct (public mixed & $data )
>
function test ( $value )
$value = & Reference :: get ( $value ); // values OR reference
$value = «test- $value » ;
return $value ;
>
echo test ( 1 ), PHP_EOL ; // test-1
$val = 2 ;
echo test ( Reference :: create ( $val )), PHP_EOL ; // test-2
echo $val , PHP_EOL ; // test-2
#### Problem solving 2 ####
class TestCall
static function __callStatic ( $name , $arguments )
$value = & Reference :: get ( $arguments [ 0 ]);
$value = » $name — $value » ;
return $value ;
>
>
echo TestCall :: test ( 3 ), PHP_EOL ; // test-3
$val = 4 ;
echo TestCall :: test ( Reference :: create ( $val )), PHP_EOL ; // test-4
echo $val , PHP_EOL ; // test-4
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 :
function use_reference ( $someParam , & $param =& $POST )
.
>
?>
But this one will work :
function use_reference ( $someParam , & $param = null )
?>
So here is a workaround to have a default value for reference parameters :
$array1 = array ( ‘test’ , ‘test2’ );
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.
If you changed a reference variable with a new `Address`, the variable it originally pointed to won’t change.
Beware of using references with anonymous function and «use» keyword :
If you have a PHP version between 5.3 and < 5.3.10, "use" keyword break the reference :
$arg = 1 ;
echo ‘withRef — BEFORE — ‘ . $arg . «\n» ; // 1
withRef ( $arg );
// in PHP 5.3 < 5.3.10 : display 1
// in PHP 5.3 >= 5.3.10 : display 2
echo ‘withRef — AFTER — ‘ . $arg . «\n» ;
?>
A workaround is to use a copy of the reference variable in «use» keyword :
.
$arg2 = $arg ;
$func = function() use( $arg2 ) < /* do nothing, just declare using $arg2 */ >;
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.
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
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’
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
I hope this is somehow useful