Man kann Variablen an Funktionen per Referenz übergeben, so dass die Funktion ihre Argumente modifizieren kann. Dazu benutzt man folgende Syntax:
<?php
function foo(&$var)
{
$var++;
}
$a=5;
foo($a);
// $a ist 6
?>
Folgende Dinge können per Referenz übergeben werden:
Referenzen, zurückgegeben von einer Funktion, zum Beispiel:
<?php
function &bar()
{
$a = 5;
return $a;
}
foo(bar());
?>
Alle anderen Ausdrücke sollte nicht per Referenz übergeben werden, da das Ergebnis undefiniert ist. Folgende Beispiele sind etwa ungültig:
<?php
function bar() // Beachte das fehlende &
{
$a = 5;
return $a;
}
foo(bar()); // Fatal error seit PHP 5.0.5
foo($a = 5); // Ausdruck, keine Variable
foo(5); // Fatal error
?>
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).
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
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.
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!
?>
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.
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>';
?>
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!
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.
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
?>
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!
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
?>
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
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
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!
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.
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.
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.
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" )
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 ;-)
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.