How to Pass Objects by Reference in PHP 5

How do you pass objects by reference in PHP 5?

are you required to use the & modifier to pass-by-reference?

Technically/semantically, the answer is yes, even with objects. This is because there are two ways to pass/assign an object: by reference or by identifier. When a function declaration contains an &, as in:

function func(&$obj) {}

The argument will be passed by reference, no matter what. If you declare without the &

function func($obj) {}

Everything will be passed by value, with the exception of objects and resources, which will then be passed via identifier. What's an identifier? Well, you can think of it as a reference to a reference. Take the following example:

class A
{
public $v = 1;
}

function change($obj)
{
$obj->v = 2;
}

function makezero($obj)
{
$obj = 0;
}

$a = new A();

change($a);

var_dump($a);

/*
output:

object(A)#1 (1) {
["v"]=>
int(2)
}

*/

makezero($a);

var_dump($a);

/*
output (same as before):

object(A)#1 (1) {
["v"]=>
int(2)
}

*/

So why doesn't $a suddenly become an integer after passing it to makezero? It's because we only overwrote the identifier. If we had passed by reference:

function makezero(&$obj)
{
$obj = 0;
}

makezero($a);

var_dump($a);

/*
output:

int(0)

*/

Now $a is an integer. So, there is a difference between passing via identifier and passing via reference.

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 5 passing class Object as parameter, is it always a pointer or a copy or a clone?

In PHP When you pass object as parameter, it is copy of the reference. So:

$ob = new StdClass;
$ob->var = "Lorem";

function aa($o) {
$o->var="Ipsum";
}
aa($ob);
echo $ob->var;

this will output Ipsum, but if you assign other object to that $o reference:

function aa($o) {
$o = new StdClass;
$o->var="Ipsum";
}

It will output Lorem - because $ob still points to previously created object.

By the way:
If you change function definition to function aa(&$o). Now it will output Ipsum again, because $o is reference to $ob reference :)

To sum up:
In PHP by default parameters are passed by value - also if they are objects! But! In code $ob = new StdClass;, $ob is reference to the object. So by default we will pass copy of the reference. They will point to the same objects. But if you change passed variable ($o = new StdClass;), $ob still points to the same object. That's why after that modification given example will output Lorem.

You can pass parameters by reference using ampersand (&), but in case of objects it is usually useless.

What happens when you pass an object by reference, in php, under the hood?

Any variable that holds an object is not holding the object directly. It holds an identifier of the object. Imagine it as the object living somewhere in an object pool having a number attached to it, e.g. #5. All the variable contains is "object #5". PHP knows that the variable refers to an object and that it's supposed to be object #5.

Whenever you work with such a variable holding an object reference, PHP looks up the referenced object from the object pool.

When you pass such a variable into a function, PHP makes a copy of that reference. There are then two variables holding the content "object #5". Not the object itself has been copied, just this tiny note which says "object #5".

When you pass such a variable into a function by reference, well, you're passing that note "object #5" by reference. PHP won't make a copy of it. But it's still just a variable saying "object #5", so when you're trying to work with it, PHP will look up the object from the pool.

This object reference mechanism is not the same as the & pass-by-reference mechanism. The object reference mechanism works exactly the same as all other pass-by-value operations; it's just that a value which represents a reference to an object is always being treated in a specific way (PHP has to look up the actual object elsewhere).

Passing by Reference in PHP 5.x

Let's say you want to write a function that removes certain values from an array.

function remove_elements($array, $item1, $item2, ...) {
...
}

You could copy the array and return it. But what if you want to know if anything was removed? Instead you modify the array in-place and return the number of elements removed. So:

function remove_elements(&$array) {
// remove elements
return $number_removed;
}

If you create a complex structure inside your function you may want to return a reference to it rather than a copy of it. But this is a fairly marginal case because PHP uses copy-on-write (ie its not copied until it's modified) but there are some valid use cases.

Returning by reference makes more sense when you're writing a member function of a class. You could return a reference to a data member but this can also break encapsulation.

Lastly, it's worth noting that all objects are passed and returned by reference by default. Everything else is passed and returned by value.

PHP 5 | Objects Passed by Reference / Value vs Copy on Write | When added as class property

As the manual page you link to says, the statement "objects are passed by reference" is not a good description of what is happening. A better way to think of it is that the "value" of an object is a handle, pointer, or address to something that exists in a different space.

Whether you assign it to an object property, an array element, or a normal variable, this "value" remains the same, and changes to the object are visible wherever you look at them. Copying the value uses a few bytes (the size of the pointer) but doesn't duplicate the memory of the object itself.

As a final clarification, the "write" in "copy-on-write" refers to modification of an existing value, after copying it from one place to another. So writing $foo = $bar, where $bar is an array, will not duplicate the memory used by the array, but subsequently writing $foo[0]=1; or $bar[0]=1 will, because the two copies need to be distinguished. This doesn't actually come into play in your example; if it did, it would be just the "object pointer" that was copied, so very little extra memory would be needed.

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.'
?>

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 objects in PHP assigned by value or reference?

Why not run the function and find out?

$b = new Bar;
echo $b->getFoo(5)->value;
$b->test();
echo $b->getFoo(5)->value;

For me the above code (along with your code) produced this output:

Foo #5
My value has now changed

This isn't due to "passing by reference", however, it is due to "assignment by reference". In PHP 5 assignment by reference is the default behaviour with objects. If you want to assign by value instead, use the clone keyword.

Benefit of passing by reference? (php)

Passing by reference is faster. PHP5 do pass objects by reference by default. I think under PHP 5.3, you still have to do $obj = &new Object();, but I could be wrong about that.

PHP5 do not pass array by reference. If you want to modify them in a function, you need to pass by reference.

Passing by value means that every single value is copied. For example, if you pass an array by value, it copies the array to a different memory location and every single element in it.



Related Topics



Leave a reply



Submit