Ok, I know what passing by reference is... I don't need that explained.
Say you have a function that takes in an argument by reference:
function foo(&$a){
$a = 1;
}
and you call it:
$a = 0;
foo($a); // Now $a is 1.
You can do the same exact thing passing by value:
function foo($a){
$a = 1;
return $a;
}
and you call it:
$a = 0;
$a = foo($a); // Now $a is 1.
So, what is the point of passing by reference?
To answer my own question from comments posted above and some other research:
Since only a reference to an object is passed to a function in pass-by-reference, it can be particularly useful when trying to conserve memory.
If there is such a case where you would want to alter an entity but return a different one, pass-by-reference can come in handy (although I would rather use multiple functions with return values).
Other than the two cases, I think this approach can cause confusion in large code bases and result in some nasty code.
If you know of any other reasons that I should add please comment and I'll add them here.
Related
In C++ if you pass a large array to a function, you need to pass it by reference, so that it is not copied to the new function wasting memory. If you don't want it modified you pass it by const reference.
Can anyone verify that passing by reference will save me memory in PHP as well. I know PHP does not use addresses for references like C++ that is why I'm slightly uncertain. That is the question.
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.
The short answer is use references when you need the functionality that they provide. Don't think of them in terms of memory usage or speed. Pass by reference is always going to be slower if the variable is read only.
Everything is passed by value, including objects. However, it's the handle of the object that is passed, so people often mistakenly call it by-reference because it looks like that.
Then what functionality does it provide? It gives you the ability to modify the variable in the calling scope:
class Bar {}
$bar = new Bar();
function by_val($o) { $o = null; }
function by_ref(&$o) { $o = null; }
by_val($bar); // $bar is still non null
by_ref($bar); // $bar is now null
So if you need such functionality (most often you do not), then use a reference. Otherwise, just pass by value.
Functions that look like this:
$foo = modify_me($foo);
sometimes are good candidates for pass-by-reference, but it should be absolutely clear that the function modifies the passed in variable. (And if such a function is useful, often it's because it really ought to just be part of some class modifying its own private data.)
In PHP :
objects are passed by reference1 -- always
arrays and scalars are passed by value by default ; and can be passed by reference, using an & in the function's declaration.
For the performance part of your question, PHP doesn't deal with that the same way as C/C++ ; you should read the following article : Do not use PHP references
1. Or that's what we usually say -- even if it's not "completely true" -- see Objects and references
Setup
I am borrowing a function from an open source CMS that I frequently use for a custom project.
It's purpose is not important to this question but if you want to know it's a simple static cache designed to reduce database queries. I can call getObject 10 times in one page load and not have to worry about hitting the database 10 times.
Code
A simplified version of the function looks like this:
function &staticStorage($name, $default_value = NULL)
{
static $data = array();
if (isset($data[$name])
{
return $data[$name];
}
$data[$name] = $default_value;
return $data[$name];
}
This function would be called in something like this:
function getObject($object_id)
{
$object = &staticStorage('object_' . $object_id);
if ($object)
{
return $object;
}
// This query isn't accurate but that's ok it's not important to the question.
$object = databaseQuery('SELECT * FROM Objects WHERE id = #object_id',
array('#object_id => $object_id'));
return $object;
}
The idea is that once I call static_storage the returned value will update the static storage as it is changed.
The problem
My interest is in the line $object = &staticStorage('object_' . $object_id); Notice the & in front of the function. The staticStorage function returns a reference already so I initially did not include the reference operator preceding the function call. However, without the reference preceding the function call it does not work correctly.
My understanding of pointers is if I return a pointer php will automatically cast the variable as a pointer $a = &$b will cause $a to point to the value of $b.
The question
Why? If the function returns a reference why do I have to use the reference operator to precede the function call?
From the PHP docs
Note: Unlike parameter passing, here you have to use & in both places - to indicate that you want to return by reference, not a copy, and to indicate that reference binding, rather than usual assignment, should be done for $myValue.
http://php.net/manual/en/language.references.return.php
Basically, its to help the php interpreter. The first use in the function definition is to return the reference, and the second is to bind by reference instead of value to the assignment.
By putting the & in the function declaration, the function will return a memory address of the return value. The assignment, when getting this memory address would interpret the value as an int unless explicitly told otherwise, this is why the second & is needed for the assignment operator.
EDIT: As pointed out by #ringø below, it does not return a memory address, but rather an object that will be treated like a copy (technically copy-on-write).
The PHP doc explains how to use, and why, functions that return references.
In your code, the getObject() function needs also a & (and the call as well) otherwise the reference is lost and the data, while usable, is based on PHP copy-on-write (returned data and source data point both to the same actual data until there is a change in one of them => two blocks of data having a distinct life)
This wouldn't work (syntax error)
$a = array(1, 2, 3);
return &$a;
this doesn't work as intended (no reference returned)
$a = array(1, 2, 3);
$ref = &$a;
return $ref;
and without adding the & to the function call as you said, no reference returned either.
To the question as to why... There doesn't seem to be a consistent answer.
if one of the & is missing PHP treats data as if it isn't a reference (like returning an array for instance) with no warning whatsoever
here some strangeness associated to functions returning references
PHP evolved during the years but still inherits some of the initial poor design choices. This seems to be one of them (this syntax is error prone as one may easily miss one &... and no warning ahead... ; also why not directly return a reference like return &$var;?). PHP made some progress but still, traces of poor design subsist.
You may also be interested in this chapter of the doc linked above
Do not use return-by-reference to increase performance. The engine will automatically optimize this on its own. Only return references when you have a valid technical reason to do so.
Finally, it's better not to look too much for equivalences between the pointers in C and the PHP references (Perl is closer than PHP in this regard). PHP adds a layer between the actual pointer to data and variables and references point rather to that layer than the actual data. But a reference is not a pointer. If $a is an array and $b is a reference to $a, using either $a or $b to access the array is equivalent. There is no dereference syntax, a *$b for instance like in C. $b should be seen as an alias of $a. This is also the reason a function can only return a reference to a variable.
I've been programming for quite a while with PHP. Recently I decided to try and use a framework. I happened to pick Symfony2. One of the first thing I noticed was that I've never encountered any reference operator(&). I used them frequently in my previous projects.
I've found this on php.net/manual/...
Note that in PHP5 you generally don't need the reference operator -- at all -- when dealing with class objects, because PHP5 implements objects using Instances (which are more like C pointers than PHP's references system).
Are references uncommon in frameworks, or perhaps in general in PHP5?
Edit
I know what references do and how they work. I wonder why the Symfony2 examples on the site do not use reference operators anywhere.
In fact if you use passing object as argument to function, PHP won't create copy of the object but simple points to the same place in memory where this object exists. So there is no need to use reference as long as you don't want to do some complex stuff (point to another object/variable in memory).
You should look at Object and references in PHP manual.
You can also consider the following code:
<?php
class A {
public $x= 20;
}
$a = new A();
echo $a->x."<br />";
change($a);
echo $a->x."<br />";
changeRef($a);
echo $a->x."<br />"; // you get notice in this line. $a is no longer A object
echo $a."<br />";
function change(A $b) {
$b->x = 10;
$b = 15;
}
function changeRef(A &$b) {
$b->x = 10;
$b = 15;
}
I've created 2 function change (without reference) and changeRef (with reference).
As you see when using change function even if we don't use reference, when using property assignment inside function also property of variable $a has been changed - it's because $a and $b pointed to the same place in memory. However if inside the same function I set any other object (in this case simple int) to variable $b, nothing more happened. Simple $b is now pointing to some other place in memory where 15 was placed but $a is pointing to the same place in memory as earlier.
However in send function (with reference) after assigning $b value 15 it means that $a has been also assigned the same value ($b is reference to $a) so after running this function when you try to display property of $a it's impossible no more (warning raised) because $a is no longer A object but simple int with 15 value.
I hope this clears you this issue a bit and now you understand why references don't need to be used very often when using objects.
EDIT
As you mentioned using references for arrays, PHP uses copy-on-write mechanism. So if you pass array to function or other variable as long as you don't modify it no copy will be created even if passing arrays as argument.
Consider the following code:
$arr = [1,2,3];
show($arr);
function show($a) {
foreach ($a as $item) {
echo $item;
}
}
in above case no copy of $arr will be created so there is no need to use reference in this case. So unswerving your question if you don't have to modify the array you don't need to use reference. Probably that's why Symfony doesn't use references in that cases.
In addition references make code less clear because if you don't go to function declaration you won't know that it could modify your data. So probably that's the extra reason they are not so commonly used.
Passing by Reference
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. As of PHP 5.3.0, you will get a warning saying that "call-time pass-by-reference" is deprecated when you use & in foo(&$a);. And as of PHP 5.4.0, call-time pass-by-reference was removed, so using it will raise a fatal error.
In C++ if you pass a large array to a function, you need to pass it by reference, so that it is not copied to the new function wasting memory. If you don't want it modified you pass it by const reference.
Can anyone verify that passing by reference will save me memory in PHP as well. I know PHP does not use addresses for references like C++ that is why I'm slightly uncertain. That is the question.
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.
The short answer is use references when you need the functionality that they provide. Don't think of them in terms of memory usage or speed. Pass by reference is always going to be slower if the variable is read only.
Everything is passed by value, including objects. However, it's the handle of the object that is passed, so people often mistakenly call it by-reference because it looks like that.
Then what functionality does it provide? It gives you the ability to modify the variable in the calling scope:
class Bar {}
$bar = new Bar();
function by_val($o) { $o = null; }
function by_ref(&$o) { $o = null; }
by_val($bar); // $bar is still non null
by_ref($bar); // $bar is now null
So if you need such functionality (most often you do not), then use a reference. Otherwise, just pass by value.
Functions that look like this:
$foo = modify_me($foo);
sometimes are good candidates for pass-by-reference, but it should be absolutely clear that the function modifies the passed in variable. (And if such a function is useful, often it's because it really ought to just be part of some class modifying its own private data.)
In PHP :
objects are passed by reference1 -- always
arrays and scalars are passed by value by default ; and can be passed by reference, using an & in the function's declaration.
For the performance part of your question, PHP doesn't deal with that the same way as C/C++ ; you should read the following article : Do not use PHP references
1. Or that's what we usually say -- even if it's not "completely true" -- see Objects and references
What does this code mean? Is this how you declare a pointer in php?
$this->entryId = $entryId;
Variable names in PHP start with $ so $entryId is the name of a variable.
$this is a special variable in Object Oriented programming in PHP, which is reference to current object.
-> is used to access an object member (like properties or methods) in PHP, like the syntax in C++.
so your code means this:
Place the value of variable $entryId into the entryId field (or property) of this object.
The & operator in PHP, means pass reference. Here is a example:
$b=2;
$a=$b;
$a=3;
print $a;
print $b;
// output is 32
$b=2;
$a=&$b; // note the & operator
$a=3;
print $a;
print $b;
// output is 33
In the above code, because we used & operator, a reference to where $b is pointing is stored in $a. So $a is actually a reference to $b.
In PHP, arguments are passed by value by default (inspired by C). So when calling a function, when you pass in your values, they are copied by value not by reference. This is the default IN MOST SITUATIONS. However there is a way to have pass by reference behaviour, when defining a function. Example:
function plus_by_reference( &$param ) {
// what ever you do, will affect the actual parameter outside the function
$param++;
}
$a=2;
plus_by_reference( $a );
echo $a;
// output is 3
There are many built-in functions that behave like this. Like the sort() function that sorts an array will affect directly on the array and will not return another sorted array.
There is something interesting to note though. Because pass-by-value mode could result in more memory usage, and PHP is an interpreted language (so programs written in PHP are not as fast as compiled programs), to make the code run faster and minimize memory usage, there are some tweaks in the PHP interpreter. One is lazy-copy (I'm not sure about the name). Which means this:
When you are coping a variable into another, PHP will copy a reference to the first variable into the second variable. So your new variable, is actually a reference to the first one until now. The value is not copied yet. But if you try to change any of these variables, PHP will make a copy of the value, and then changes the variable. This way you will have the opportunity to save memory and time, IF YOU DO NOT CHANGE THE VALUE.
So:
$b=3;
$a=$b;
// $a points to $b, equals to $a=&$b
$b=4;
// now PHP will copy 3 into $a, and places 4 into $b
After all this, if you want to place the value of $entryId into 'entryId' property of your object, the above code will do this, and will not copy the value of entryId, until you change any of them, results in less memory usage. If you actually want them both to point to the same value, then use this:
$this->entryId=&$entryId;
No, As others said, "There is no Pointer in PHP." and I add, there is nothing RAM_related in PHP.
And also all answers are clear. But there were points being left out that I could not resist!
There are number of things that acts similar to pointers
eval construct (my favorite and also dangerous)
$GLOBALS variable
Extra '$' sign Before Variables (Like prathk mentioned)
References
First one
At first I have to say that PHP is really powerful language, knowing there is a construct named "eval", so you can create your PHP code while running it! (really cool!)
although there is the danger of PHP_Injection which is far more destructive that SQL_Injection. Beware!
example:
Code:
$a='echo "Hello World.";';
eval ($a);
Output
Hello World.
So instead of using a pointer to act like another Variable, You Can Make A Variable From Scratch!
Second one
$GLOBAL variable is pretty useful, You can access all variables by using its keys.
example:
Code:
$three="Hello";$variable=" Amazing ";$names="World";
$arr = Array("three","variable","names");
foreach($arr as $VariableName)
echo $GLOBALS[$VariableName];
Output
Hello Amazing World
Note: Other superglobals can do the same trick in smaller scales.
Third one
You can add as much as '$'s you want before a variable, If you know what you're doing.
example:
Code:
$a="b";
$b="c";
$c="d";
$d="e";
$e="f";
echo $a."-";
echo $$a."-"; //Same as $b
echo $$$a."-"; //Same as $$b or $c
echo $$$$a."-"; //Same as $$$b or $$c or $d
echo $$$$$a; //Same as $$$$b or $$$c or $$d or $e
Output
b-c-d-e-f
Last one
Reference are so close to pointers, but you may want to check this link for more clarification.
example 1:
Code:
$a="Hello";
$b=&$a;
$b="yello";
echo $a;
Output
yello
example 2:
Code:
function junk(&$tion)
{$GLOBALS['a'] = &$tion;}
$a="-Hello World<br>";
$b="-To You As Well";
echo $a;
junk($b);
echo $a;
Output
-Hello World
-To You As Well
Hope It Helps.
That syntax is a way of accessing a class member. PHP does not have pointers, but it does have references.
The syntax that you're quoting is basically the same as accessing a member from a pointer to a class in C++ (whereas dot notation is used when it isn't a pointer.)
To answer the second part of your question - there are no pointers in PHP.
When working with objects, you generally pass by reference rather than by value - so in some ways this operates like a pointer, but is generally completely transparent.
This does depend on the version of PHP you are using.
You can simulate pointers to instantiated objects to some degree:
class pointer {
var $child;
function pointer(&$child) {
$this->child = $child;
}
public function __call($name, $arguments) {
return call_user_func_array(
array($this->child, $name), $arguments);
}
}
Use like this:
$a = new ClassA();
$p = new pointer($a);
If you pass $p around, it will behave like a C++ pointer regarding method calls (you can't touch object variables directly, but that's evil anyways :) ).
entryId is an instance property of the current class ($this)
And $entryId is a local variable
Yes there is something similar to pointers in PHP but may not match with what exactly happens in c or c++.
Following is one of the example.
$a = "test";
$b = "a";
echo $a;
echo $b;
echo $$b;
//output
test
a
test
This illustrates similar concept of pointers in PHP.
PHP passes Arrays and Objects by reference (pointers). If you want to pass a normal variable Ex. $var = 'boo'; then use $boo = &$var;.
PHP can use something like pointers:
$y=array(&$x);
Now $y acts like a pointer to $x and $y[0] dereferences a pointer.
The value array(&$x) is just a value, so it can be passed to functions, stored in other arrays, copied to other variables, etc. You can even create a pointer to this pointer variable. (Serializing it will break the pointer, however.)