I probably should have, but I've never seen this before. Ran into it when looking over the documenation of a Smarty Plugin.
$smarty =& new Smarty;
The =& sign in particular. If you enter it in Google, it gets ignored, just like any other search engine. What is this used for?
Same goes for this function signature:
function connect(&$smarty, $reset = false)
Why the & symbol?
Actually, this code is written to be compatible with PHP 4. The ampersand is useless in PHP 5 (as Tim said - since PHP 5, all objects are passed by reference).
With PHP 4, all variables were passed by value.
If you wanted to pass it by reference, you had to declare a reference assignment :
$ref_on_my_object =& new MyObject();
This code is still accepted with PHP 5 default configuration, but it's better to write :
$ref_on_my_object = new MyObject(); // Reference assignment is implicit
For your second problem, the issue is "almost" the same...
Because PHP lets you declare function arguments (resp. types), and you can't do it for return values.
An accepted, but "not so good" practice is to avoid reference declaration within the function's declaration :
function foo($my_arg) {
// Some processing
}
and to call with a reference...
$my_var;
$result = foo( &$my_var );
// $my_var may have changed because you sent the reference to the function
The ideal declaration would be more like :
function foo( & $my_input_arg ) {
// Some processing
}
then, the call looses the ampersand :
$my_var;
$result = foo( $my_var );
// $my_var may have changed because you sent the reference to the function
It is used for passing values by reference rather than by value which is default in php.
& passes an argument by reference. In this fashion, connect() can manipulate the $smarty object so that the calling function can retrieve the modified object.
Similarly, =& sets a variable by reference.
As Tim said its a reference to a variable. But if you're using a recent version of PHP then all class object are passed by reference anyway. You would still need this if you were passing about arrays, or other builtin types though.
The first example is returning reference, the second is passing reference.
You can read all about it in the PHP manual
& is PHP's reference operator. It's used to return a reference to the object. In this case "new Smarty".
The ampersand will assign a reference to the variable, rather than the value of the object.
One of the primary uses of the ampersand operator is to pass by memory address. This is usually something you do when you want to have a variable changed, but not be returned.
function test_array(&$arr)
{
$varr[] = "test2";
}
$var = array('test');
test_array($var);
print_r($var);
this should output
array( test , test2 );
The purpose of this is usually when you need to pass the actual copy[memory address] you are working with into another function / object. Typically it was used in the past to alleviate a lack of memory and speed up performance, it's a feature from C / C++ and a few other low level languages.
Related
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'm using the Facebook library with this code in it:
class FacebookRestClient {
...
public function &users_hasAppPermission($ext_perm, $uid=null) {
return $this->call_method('facebook.users.hasAppPermission',
array('ext_perm' => $ext_perm, 'uid' => $uid));
}
...
}
What does the & at the beginning of the function definition mean, and how do I go about using a library like this (in a simple example)
An ampersand before a function name means the function will return a reference to a variable instead of the value.
Returning by reference is useful when
you want to use a function to find to
which variable a reference should be
bound. 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.
See Returning References.
It's returning a reference, as mentioned already. In PHP 4, objects were assigned by value, just like any other value. This is highly unintuitive and contrary to how most other languages works.
To get around the problem, references were used for variables that pointed to objects. In PHP 5, references are very rarely used. I'm guessing this is legacy code or code trying to preserve backwards compatibility with PHP 4.
This is often known in PHP as Returning reference or Returning by reference.
Returning by reference is useful when you want to use a function to
find to which variable a reference should be bound. 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.
PHP documentation on Returning reference
A reference in PHP is simply another name assigned to the content of a variable. PHP references are not like pointers in C programming, they are not actual memory addresses, so they cannot be used for pointer arithmetics.
The concept of returning references can be very confusing especially to beginners, so an example will be helpful.
$populationCount = 120;
function &getPopulationCount() {
global $populationCount;
return $populationCount;
}
$countryPopulation =& getPopulationCount();
$countryPopulation++;
echo "\$populationCount = $populationCount\n"; // Output: $populationCount = 121
echo "\$countryPopulation = $countryPopulation\n"; //Output: $countryPopulation = 121
The function getPopulationCount() defined with a preceding &, returns the reference to the content or value of $populationCount. So, incrementing $countryPopulation, also increments $populationCount.
Take the following code from CodeIgniter's show_error function:
$_error =& load_class('Exceptions', 'core');
The documentation for the load_class function says it acts as a singleton. The function basically takes the given parameters and searches for a class in the appropriate path. It then includes the file if it exists. The function is declared as:
function &load_class(...)
Why does it have the & and what is its purpose? Is $_error declared as such as a result of defining the function like that?
I don't see any point of declaring and using load_class like that. From the source code of load_class(), we can see that it caches loaded objects in an array with the class name as the key. If it is not in the cache, it loads an object given a name, and then stores that object reference into the array. In both cases, it returns the element of the array (by reference).
Returning by reference allows the caller to have a reference to the element of the array. The only things that this allows us to do are:
See later changes to that array element (i.e. the value associated with that key) from the outside reference we have. But this is not applicable, since the load_class function never changes the value associated with a key after it sets it.
Have external code be able to change the element in the array, without the load_class function knowing about it. But this would be a highly dubious practice, to mess with the cache from the outside, and I highly doubt this is something the authors wanted.
So there is no legitimate reason to return by reference. My guess is that it is a leftover from PHP 4, when objects were values, and so assigning or returning an "object value" would copy it. In PHP 5, objects are not values; you can only manipulate them through object references, and assigning or returning an object reference by value never copies the object it points to.
The php documentation seems to explain why you have to uses =& even though the function is marked to return a refrence function &load_class
Returning References
Returning by reference is useful when you want to use a function to
find to which variable a reference should be bound. 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. To return references, use
this syntax:
<?php class foo {
public $value = 42;
public function &getValue() {
return $this->value;
}
}
$obj = new foo;
$myValue = &$obj->getValue(); // $myValue is a reference to $obj->value, which is 42.
$obj->value = 2;
echo $myValue;
// prints the new value of $obj->value, i.e. 2. ?>
In this example,
the property of the object returned by the getValue function would be
set, not the copy, as it would be without using reference syntax.
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.
If you are asking what references in general are the documentation explains.
function do_sth_with_var($variable) {
if (is_by_reference($variable)) {
$variable = something($variable)
}
else {
return something($variable);
}
}
so for example if 'something' was strtoupper:
do_sth_with_var(&$str); // would make $str uppercase, but
$str = do_sth_with_var($str); // that way should it be done if ommitting that '&'
Disclaimer: This does not directly answer the OP's question, but I'm providing this answer in the hope that it will help him/her.
I'd say, provide a consistent interface. Declare the function parameter as reference:
function do_sth_with_var(&$variable) {
and it will always be a reference.
You could also to the contrary and always copy the value:
function do_sth_with_var($variable) {
$val = $variable;
// work with $val here
return $val;
}
No built-in PHP function I know changes its behaviour based on whether you pass a reference or not. They are clearly defined to either treat an argument as reference or not and I would argue that users are used to this clear definitions and can deal with them.
For example, sort always sorts an array in place. You know that. So if you want to keep the original, you make a copy before the call.
It depends on your function whether it makes sense to perform an in-place operation or not. E.g. it makes sense for sort but I'd say it does not make sense for string processing.
Also, as you are using PHP 5.3, passing variables by reference at call-time is deprecated:
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);.
So you (or whoever) should not do that anyway.
calltime-pass-by-ref is considered deprecated as of 5.3.
apart from that ... answering the question academically; I don't think there is any way to determine that propperly, b/c there is no difference between a "reference" and a usual parameter. In PHP every variable is a pointer to section in the symbol table. A reference just makes another variable point to the same section.
in PHP there are no references as C knows them for example. every variable is a pointer and every "reference" too.
PS: #Gordon: I forgot about the Reflection-Classes. Of course, they work on a meta-level. My answer is more directed at how PHP actually deals with paramters and variables.
This topic is covered very well by the first comment here (official php manual)
to answer your question literally, you can try experimenting with debug_zval_dump. Refcounts will be different for by val and by reference parameters.
function xxx($a) {
debug_zval_dump($a);
}
$b = 123;
xxx($b); // long(123) refcount(4)
xxx(&$b); // long(123) refcount(1)
In your specific case you don't need to know if the value is passed by reference or not you can do something like:
function do_sth_with_var($variable) {
$variable = something($variable)
return $variable;
}
It should do exactly what you ask in your question
I don't know any good and safe way to control that a passed parameter is a reference and not just a value inside the body of a function at running time.
References:
If I pass a variable to a function (e.g. $var), is that supposed to be a copy of a reference to the actual variable (such that setting it null doesn't affect other copies)?
Or is it receiving a reference to what is a new copy of the actual variable (such that setting it to null destroys its copy only)?
If the latter, does this copy objects and arrays in memory? That seems like a good way to waste memory and CPU time, if so.
I think can understand passing by reference (e.g. &$var) correctly by knowing how this works, first.
Scope:
What's the deal with local scope? Am I right in observing that I can declare an array in one function and then use that array in other functions called within that function WITHOUT passing it to them as a parameter?
Similarly, does declaring in array in a function called within a function allow it to be available in the caller?
If not, does scoping work by a call stack or whatever like every bloody thing I've come to understand about programming tells me it should?
PHP is so much fun. :(
If I pass a variable to a function (e.g. $var), is that supposed to be a copy of a reference to the actual variable (such that setting it null doesn't affect other copies)?
Depends on the function. And also how you call it. Look at this example:
http://www.ideone.com/LueFc
Or is it receiving a reference to what is a new copy of the actual variable (such that setting it to null destroys its copy only)?
Again depends on the function
If the latter, does this copy objects and arrays in memory? That seems like a good way to waste memory and CPU time, if so.
Its going to save memory to use a reference, certainly. In php>4 it always uses reference for objects unless you specify otherwise.
What's the deal with local scope? Am I right in observing that I can declare an array in one function and then use that array in other functions called within that function WITHOUT passing it to them as a parameter?
No you can't.
Similarly, does declaring in array in a function called within a function allow it to be available in the caller?
No, it doesn't.
If not, does scoping work by a call stack or whatever like every bloody thing I've come to understand about programming tells me it should?
If you want to use a variable from outside the function, before using it, you'd write global $outsidevar
Concerning your first set of questions:
foo($a);
function foo($b) { echo $b; }
In this case, $a will not be copied to a new variable $b, only because it is passed by value.
This is because PHP uses the copy-on-write concept. PHP will not copy the contents of a variable, unless they are changed. Instead PHP will increment the refcount property of the existing "zval" of $a.
Well, the whole thing is not that trivial, but to answer your question: No, it does not copy the variable, unless you write to it in the function and no, you won't save CPU and Memory by using a reference. In most cases the reference won't change performance at all, but in the worst case it will actually degrade it (because if a not is_ref variant of the variable already exists and a reference is created the value of the variable must be copied to get a zval with is_ref and one without). Optimizing code by using references is no good.
if argument to a function is defined as so "function my_function($variable) {}" then you are getting a copy of the variable and any alterations made to the variable inside your function will not be available to the function caller. you can pass a variable by reference by prepending an ampersand to the argument when defining your function and thus any alterations made to the variable will persist to the function caller, ie "function my_function(&$variable) {}"
function myfunction($var) {
$var = 'World';
}
$var = 'Hello';
myfunction($var);
echo $var; // 'Hello';
Passing a variable by reference
function myfunction(&$var) {
$var = 'World';
}
$var = 'Hello';
myfunction($var);
echo $var; // 'World'