Are PHP Variables Passed by Value or by Reference

Are PHP Variables passed by value or by reference?

It's by value according to the PHP Documentation.

By default, function arguments are passed by value (so that if the value of the argument within the function is changed, it does not get changed outside of the function). To allow a function to modify its arguments, they must be passed by reference.

To have an argument to a function always passed by reference, prepend an ampersand (&) to the argument name in the function definition.

<?php
function add_some_extra(&$string)
{
$string .= 'and something extra.';
}

$str = 'This is a string, ';
add_some_extra($str);
echo $str; // outputs 'This is a string, and something extra.'
?>

Why are my variables passed by reference?

PHP passes all object by reference, by default.

More informations here : http://php.net/manual/en/language.oop5.references.php

Are php resources passed by reference?

A resource is not the actual connection. A resource is nothing more than a pointer to a connection. So when you close the connection belonging to this resource, there is no difference in behavior if it was original or a copied one.

Are PHP5 objects passed by reference?

Objects are passed (and assigned) by reference. No need to use address of operator.

Granted what I typed is an oversimplification but will suit your purposes. The documentation states:

One of the key-points of PHP5 OOP that
is often mentioned is that "objects
are passed by references by default".
This is not completely true. This
section rectifies that general thought
using some examples.

A PHP reference is an alias, which
allows two different variables to
write to the same value. As of PHP5,
an object variable doesn't contain the
object itself as value anymore. It
only contains an object identifier
which allows object accessors to find
the actual object. When an object is
sent by argument, returned or assigned
to another variable, the different
variables are not aliases: they hold a
copy of the identifier, which points
to the same object.

For a more detailed explanation (explains the oversimplification as well as identifiers) check out this answer.

PHP: Why should only variables be passed by reference?

Finally I found a great explanation which helped me to understand this: What's the difference between passing by reference vs. passing by value?

As Daniel Pryden states:

In simplest terms:

  • call by value means that you pass values as function arguments
  • call by reference means that you pass variables as function arguments

In metaphoric terms:

  • Call by value is where I write down something on a piece of paper and hand it to you. Maybe it's a URL, maybe it's a complete copy of
    War and Peace. No matter what it is, it's on a piece of paper which
    I've given to you, and so now it is effectively your piece of paper.
    You are now free to scribble on that piece of paper, or use that piece
    of paper to find something somewhere else and fiddle with it,
    whatever.
  • Call by reference is when I give you my notebook which has something written down in it. You may scribble in my notebook (maybe I
    want you to, maybe I don't), and afterwards I keep my notebook, with
    whatever scribbles you've put there. Also, if what either you or I
    wrote there is information about how to find something somewhere else,
    either you or I can go there and fiddle with that information.

In this case the notice "Only variables should be passed by reference" is still unjustified as we are only interested in retrieving the last value of the array. However the function end() is defined like

mixed end ( array &$array )

The & sign which states passing by reference is there for a certain reason: end() is not just returning the last element of an array, it also changes its internal pointer to the end. Therefore the array is modified.

If we only would return the last element of an array without touching the array there would be no need to pass the array by reference and we would not get this notice. But end() is somehow the wrong function for that.

What if there is no justification for me getting this notice?
Note that also the function to be called might be defined wrong. In my case I hade a function defined like this:

/**
* Flatten an array by one level if only needing a certain key value from a sub array.
*
* Example: [["foo"=>"bar","foo"=>"cheese"]]
* Result: ["bar","cheese"]
*
* @param $array: The input array.
* @param $key: The key to flatupshift. Default is 0.
* @return $array: The result
*/
private function array_flatupshift(&$array, $key = 0) {
$a = [];
foreach ($array as $item) {
if (is_object($item)) {
array_push($a, $item->$key);
} else if (is_array($item)) {
array_push($a, $item[$key]);
}
}
return $a;
}

This is simply a wrong function definition. So if you also get notices like this: Check if the function you call is defined correctly. Passing by reference does not make sense here as the array being passed is not touched in any way. Therefore the function definition should be without the "reference &/":

private function array_flatupshift($array, $key = 0) {

There are some cases where you MIGHT use the error control operator if you know what you are doing. Therefore:

$string = "hi-dude";
echo @end(explode('-', $string));

... would be o.k. I guess is the result of explode is not needed anymore. However notice the drawbacks of suppressing all possible errors. Please correct me if I go wrong here.

Objects are passed by reference. Parameters to call_user_func aren't. What gives?

Parameters passing

The main issue is - that parameters, passed to call_user_func() will be passed as values - so they will be copy of actual data. This behavior overrides the fact, that

objects are passed by reference. Note:

Note that the parameters for call_user_func() are not passed by
reference.

Tracking error

You're not fully correct about "silent agreement" in such cases. You will see error with level E_WARNING in such cases:


Warning: Parameter 1 to with_ref() expected to be a reference, value given in

So - you will be able to figure out that you're mixing reference and values passing

Fixing the issue

Fortunately, it's not too hard to avoid this problem. Simply create reference to desired value:

class Example {
function RunEvent($event) {
if (isset($this->events[$event])) {
foreach ($this->events[$event] as $k => $v) {

$obj = &$this;
call_user_func($v, $obj);
}
}
}
}

-then result will be quite as expected:


object(Example)#1 (3) {
["events"]=>
array(1) {
["example"]=>
array(2) {
[0]=>
string(8) "with_ref"
[1]=>
string(11) "without_ref"
}
}
["with_ref"]=>
bool(true)
["without_ref"]=>
bool(true)
}

Are arrays in PHP copied as value or as reference to new variables, and when passed to functions?

For the second part of your question, see the array page of the manual, which states (quoting) :

Array assignment always involves value
copying. Use the reference operator to
copy an array by reference.

And the given example :

<?php
$arr1 = array(2, 3);
$arr2 = $arr1;
$arr2[] = 4; // $arr2 is changed,
// $arr1 is still array(2, 3)

$arr3 = &$arr1;
$arr3[] = 4; // now $arr1 and $arr3 are the same
?>



For the first part, the best way to be sure is to try ;-)

Consider this example of code :

function my_func($a) {
$a[] = 30;
}

$arr = array(10, 20);
my_func($arr);
var_dump($arr);

It'll give this output :

array
0 => int 10
1 => int 20

Which indicates the function has not modified the "outside" array that was passed as a parameter : it's passed as a copy, and not a reference.

If you want it passed by reference, you'll have to modify the function, this way :

function my_func(& $a) {
$a[] = 30;
}

And the output will become :

array
0 => int 10
1 => int 20
2 => int 30

As, this time, the array has been passed "by reference".



Don't hesitate to read the References Explained section of the manual : it should answer some of your questions ;-)

PHP parameter variable vs reference

A parameter passage by value - value of a variable is passed.

$b = 1;
function a($c) {
$c = 2; // modifying this doesn't change the value of $b, since only the value was passed to $c.
}

a($b);
echo $b; // still outputs 1

A parameter pass by reference? - a pointer to a variable is passed.

$b = 1;
function a($c) {
$c = 2; // modifying this also changes the value of $b, since variable $c points to it
}

a($b);
echo $b; // outputs 2 now after calling a();

When is it good to use pass by reference in PHP?

The following does not apply to objects, as it has been already stated here. Passing arrays and scalar values by reference will only save you memory if you plan on modifying the passed value, because PHP uses a copy-on-change (aka copy-on-write) policy. For example:

# $array will not be copied, because it is not modified.
function foo($array) {
echo $array[0];
}

# $array will be copied, because it is modified.
function bar($array) {
$array[0] += 1;
echo $array[0] + $array[1];
}

# This is how bar shoudl've been implemented in the first place.
function baz($array) {
$temp = $array[0] + 1;
echo $temp + $array[1];
}


# This would also work (passing the array by reference), but has a serious
#side-effect which you may not want, but $array is not copied here.
function foobar(&$array) {
$array[0] += 1;
echo $array[0] + $array[1];
}

To summarize:

  • If you are working on a very large array and plan on modifying it inside a function, you actually should use a reference to prevent it from getting copied, which can seriously decrease performance or even exhaust your memory limit.

  • If it is avoidable though (that is small arrays or scalar values), I'd always use functional-style approach with no side-effects, because as soon as you pass something by reference, you can never be sure what passed variable may hold after the function call, which sometimes can lead to nasty and hard-to-find bugs.

  • IMHO scalar values should never be passed by reference, because the performance impact can not be that big as to justify the loss of transparency in your code.



Related Topics



Leave a reply



Submit