Why is the variable passed by reference not changed when the assignment is also made with a reference?
function foo(&$x) {
$y = 1;
$x = &$y;
}
$bar = 0;
foo($bar);
echo $bar; //why is this not 1?
This behavior seems to be identical in all PHP versions. Therefore I assume that the behavior is by design.
Is it documented somewhere that the reference is lost in such cases?
References in PHP are a means to access the same variable content by different names. They are not like C pointers; for instance, you cannot perform pointer arithmetic using them, they are not actual memory addresses, and so on. [..] Instead, they are symbol table aliases. Note that in PHP, variable name and variable content are different, so the same content can have different names. The closest analogy is with Unix filenames and files - variable names are directory entries, while variable content is the file itself. References can be likened to hardlinking in Unix filesystem.
What References Are
<?php
$a =& $b;
?>
it means that $a and $b point to the same content.
Note:
$a and $b are completely equal here. $a is not pointing to $b or vice versa. $a and $b are pointing to the same place.
What References Do
So, $x = &$y; makes $x an alias of the value that $y is pointing to. If $x was an alias to some value before, that's broken now, because it can only point to one value at a time.
However, it feels wrong that you can destroy the passed by reference relationship.
Well, that's entirely up to you. If you understand how references work, then you are entirely in control of writing code that makes them work as you want them to.
A variable is a name assigned to a value. You pass or use a variable by retrieving its value and work with this or by its name for later refering to it. Passing by reference has the problem that other processes may change the variable's value while you are working with it. If you are passing by value, you give a new name to the value and have good chances that no other process will know this name and do unwanted things with the associated value.
What is not possible is to make e.g. "x" first a reference to "bar" and then "x" a reference to "y" and then expect the name "bar" to be a new name for the value of "y". In other word you first said "with x I mean bar", then "with x I mean y", and then "give me the value assigned to bar". Where should be a change of the value assigned to "bar"? It's nothing else than
$bar = 0;
$x = &$bar;
$y = 1;
$x = &$y;
echo $bar; // 0
What you expect from your function would require to explicitly "re-establish" the association between "x" and "bar" by assigning "bar" to "x":
$bar = 0;
$x = &$bar;
$y = 1;
$x = &$y;
$bar = &$x;
echo $bar; // 1
Consider that your function foo(&$x) effectively is "function foo($x = &$bar)" (of course formally not possible to state). This makes clear that you have two competing $x = &, the winning last one fully overwriting the losing first one.
Related
References in PHP are a means to access the same variable content by different names and they are not actual memory addresses. Instead, they are symbol table aliases. And, 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.
On the other hand, I know, an identifier is a name given to an entity (not memory location like references in PHP). Can you explain the differences between 'identifier' and 'references' in PHP in this context?
Let us start with the last part of your quotation.
And, 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.
Object Identifiers
In general, an object identifier is an integer value that identifies an object. Let us create some objects from a bare class A. We would use SPL's spl_object_id() and var_dump() functions.
Both functions return the object handle for the given object. The object handle is not a memory address.
class A {}
$a = new A();
$b = $a;
var_dump($a) . PHP_EOL;
var_dump($b) . PHP_EOL;
// object(A)#1 (0) { Notice #1 - an identifier
// }
// object(A)#1 (0) { Notice #1 - an identifier
// }
echo spl_object_id($a) . PHP_EOL; // Outputs: 1 - an identifier
echo spl_object_id($b) . PHP_EOL; // Outputs: 1 - an identifier
$a and $b hold a copy of the identifier, which points to the same object (A).
If a PHP script created 500 objects, then each object id would be unique for the lifetime of the object. Each object id can be used as a key for storing objects, or for identifying an object, as long as the object is not destroyed/garbage collected. Once the object is destroyed, its id may be reused for other objects.
Now, let us start with the first part of your quotation.
References in PHP are a means to access the same variable content by
different names and they are not actual memory addresses. Instead,
they are symbol table aliases.
Reference
In PHP, reference has a different meaning. Therefore, it allows you to access a value with different variable names. A reference is created by the & operator in PHP:
$a = 12;
// Notice the & (ampersand)
$b = & $a; // $b = 12;
$b = 20; // $a = 20; now
Here we can access the value 20 using $a and $b. Ok! We now need to know what happens when we assign a value to a variable because you quoted that the different variable names are not actually memory address. Let us dig into that.
zval Container
A PHP variable is stored in a container called a zval. A zval container is created when a new variable is created with a constant value, such as:
$a = "hello";
A zval container stores four types of information about a variable:
Type - variable's type
Value - variable's value
is_ref - a boolean value representing whether or not the variable is part of a "reference set"
refcount - holds how many variable names (also called symbols) point to this one zval container
There is a function named xdebug_debug_zval() which is available when Xdebug is installed; It helps you dig into how a variable with a value resides in a zval container.
$a = "hello";
xdebug_debug_zval('a');
This outputs as the following:
a: (refcount=1, is_ref=0)='hello'
Or graphically you can imagine the zval container as the following:
Symbol Table
The zval container does not include variable names. Those are stored in what is called a symbol table. In the symbol table our "Reference" section's exmaple looks like:
symbol | value
-------+------
a, b | 20
So a and b symbols are aliases here. This happens for the scalar types only.
There are four types of scope in PHP - local, global, static, and function parameters. There is a symbol table for each level of scope. As opposed to scalar values, arrays and objects store their properties in a symbol table of their own. In the symbol table, our "Object Identifiers" section's example looks like:
$a = new A();
$b = $a;
symbol | value object | details
-------+--------- -------------+--------
a | object(A)#1 object(A)#1 | class A { ... }
b | object(A)#1
Here a and b symbols are not aliases. They hold a copy of the identifier, which points to the same object.
References:
https://www.php.net/manual/en/features.gc.refcounting-basics.php
http://www.levijackson.net/php-zvals-and-symbol-tables/
Objects and references in php 5
https://github.com/php/php-src/pull/2611
https://github.com/php/php-src/commit/5097e2ee13de12b4445b4123e1554c0733c6853c
Refrence in php means you are allowing the value of specfic variable to be changed in the further code or processing like
$x =& $y
Or
$x = &$y
Both of these allow the value of $x to be changed if the value of $y is changed in the further code.
Whereas identifiers are simply a name assigned and cannot change its value in the further process.
What does the =& (equals-ampersand) assignment operator do in PHP?
Is it deprecated?
It's not deprecated and is unlikely to be. It's the standard way to, for example, make part of one array or object mirror changes made to another, instead of copying the existing data.
It's called assignment by reference, which, to quote the manual, "means that both variables end up pointing at the same data, and nothing is copied anywhere".
The only thing that is deprecated with =& is "assigning the result of new by reference" in PHP 5, which might be the source of any confusion. new is automatically assigned by reference, so & is redundant/deprecated in$o = &new C;, but not in $o = &$c;.
Since it's hard to search, note that =& (equals ampersand) is the same as = & (equals space ampersand) and is often written such that it runs into the other variable like $x = &$y['z']; or $x = &$someVar (ampersand dollar sign variable name). Example simplified from the docs:
$a = 3;
$b = &$a;
$a = 4;
print "$b"; // prints 4
Here's a handy link to a detailed section on Assign By Reference in the PHP manual. That page is part of a series on references - it's worth taking a minute to read the whole series.
It's two different operators. = is assignment as you probably know. And & means the variable should be accessed by reference rather than by value.
$x = &$y['z'];
also has the effect of creating $y['z'] if it doesn't exist, and setting it to null.
This prevents error messages that you might have wanted to read. I haven't found documentation on this yet; possibly new in 5.3, for all I know.
The symbol & is used in various ways in PHP to represent operations with "references". The PHP manual has a section titled References Explained which every PHP programmer should read.
It's important to understand that references in PHP are not a data type, like a pointer, but a concept regarding how variables work. There is therefore no single meaning of & - you should not read it as "make a reference" - it just means "something reference-y is happening here".
In particular, the syntax $a =& $b, which can also be written $a = &$b, represents assignment by reference. It binds two variables together, so that they both point at the same piece of data. Think of the & as modifying the = rather than modifying the $b.
Once you've bound two variables together in this way, they are interchangeable - you can't say that "$a points to $b" or "$b points to $a":
$a =& $b;
$a = 42;
// both $a and $b will be 42
$b = 101;
// both $a and $b will be 101
You can also link more than two variables together as references, and again it doesn't matter which of the existing names you use on the right-hand side of the assignment:
$a =& $b;
$c =& $b;
$d =& $a;
$e =& $c;
// $a, $b, $c, $d, and $e now all point to the same data, interchangeably
However, if you put the same variable on the left-hand side, it breaks the existing link of that variable, and links it to something else:
$a =& $b;
// $a and $b are linked together
$a =& $c;
// $a is now linked to $c
// the value of $b doesn't change, but it is not linked to $a or $c
To "break" the link without making a new link, you can use the unset keyword:
$a =& $b;
$c =& $a;
// $a, $b, and $c are all linked together
unset($a);
// $b and $c are still linked together, but $a is independent
Some descriptions refer to =& as "creating or adding to a reference set". Perhaps it would have been better if it had been implemented as a function, like bind($a, $b) to highlight that both arguments are affected by the operation.
I'd like to draw some attention to the semantics and code styling of "Assigning By Reference". The OP's opening sentence hints toward a misconception:
What does the =& (equals-ampersand) assignment operator do in PHP?
First, let's review the dedicated section of the PHP Docs page for Assignment Operators. Notice how the = comes before the & and that the two symbols are separated. This is because they are NOT "combined operators". Semantically, it is "assigning" a "reference"; it is not a "reference assignment operator".
Second, look at how ALL of the "combined operators" are written lower on the docs page. The = is consistently the right-most symbol. This is a very important distinction because writing the & on the left of the = changes the meaning -- it becomes a combined operator ("bitwise and assignment operator") instead of an assignment to a reference.
PSR coding standards should be something that all PHP developers are aware of and strive to obey. Notice this rule of PSR-12 Section 6.2:
All binary arithmetic, comparison, assignment, bitwise, logical, string, and type operators MUST be preceded and followed by at least one space
By this rule, there should always be a space after the = operator -- this makes =& a violation.
Furthermore, there are other rules that state that there should not be a space between & and its variable/argument/function/etc.
When using the reference operator & before an argument, there MUST NOT be a space after it
TL;DR
When assigning a reference, always write the = with spaces on both sides and never write a space after &.
Bad: $a =& $b;
Good: $a = &$b;
Demonstrated consistently/correctly: https://riptutorial.com/php/example/11991/assign-by-reference
Not demonstrated consistently/correctly:
https://www.php.net/manual/en/language.references.whatdo.php#:~:text=$a%20=%26%20$b;
https://www.php.net/manual/en/language.references.whatdo.php#:~:text=$foo%20=%26%20find_var($bar);
https://www.php.net/manual/en/language.oop5.basic.php#:~:text=$reference%20%20=%26%20$instance;
I have a library class class someClass{....}. I created an object for this class.
$objectA = someClass;
I would like to use an alias for $objectA to some thing like $objectB, hence my class is more meaningful.
PS: $objectB should point $objectA
$objectB = $objectA;
From the manual:
One of the key-points of PHP 5 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 PHP 5, 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.
<?php
class A {
public $foo = 1;
}
$a = new A;
$b = $a; // $a and $b are copies of the same identifier
// ($a) = ($b) = <id>
$b->foo = 2;
echo $a->foo."\n";
$c = new A;
$d = &$c; // $c and $d are references
// ($c,$d) = <id>
$d->foo = 2;
echo $c->foo."\n";
$e = new A;
function foo($obj) {
// ($obj) = ($e) = <id>
$obj->foo = 2;
}
foo($e);
echo $e->foo."\n";
?>
The above example will output:
2
2
2
I like John Conde's answer. I would like to add the following (to make it more straightforward):
In PHP almost anything can be "referenced". It is a similar concept to a "pointer" for old folks like me who came from the roots of technology programming in C and ASM.
A "pointer" is the address of the physical location of something in memory. By knowing it, you can reference that content without using the variable in the context.
In PHP, if you precede objects, structures, or variables with the symbol "&" you are telling the interpreter that you want the reference of the content and not the content itself. When associating it to another object, structure, or variable, instead of making a copy of it in another memory allocation point, the PHP interpreter will reference it to the same memory location as the original. Mainly, you will end up with two items pointing to the same location in RAM.
You can reference variables, structures, and objects in PHP like this:
$variable = "Variable Content";
$alias = &$variable;
echo $alias;
The above code should print Variable Content.
Please, notice that $alias = &$variable; is NOT the same as $alias = $variable; (without the "&"). In the first case, PHP will duplicate the content of $variable in $alias, and you will have two identical values in different locations of RAM being pointed by different variables. The second case, using "&", is a single content with two pointers that are independent but reference to the same location in RAM.
Similarly with how it happens with two specific variables, if you unset either of them ($variable or $alias) it won't unset the reference, which means the other will continue working. But, if you modify any, it will modify the content for both variables because they are looking to the same physical location in RAM to retrieve the content when used.
Think about this as analogous to the Unix unlink call. The same rule applies to objects and structures. Everything is referenceable.
And, YES, you can have multiple references to the same single content.
If you are now suddenly thinking about a "garbage collection" (GC) nightmare, well, so you got it. :)
More at https://www.php.net/manual/en/language.references.php
Those are similar in concept, varying only in terms of implementation and language model:
Referecences = Alias = Pointer
What does the =& (equals-ampersand) assignment operator do in PHP?
Is it deprecated?
It's not deprecated and is unlikely to be. It's the standard way to, for example, make part of one array or object mirror changes made to another, instead of copying the existing data.
It's called assignment by reference, which, to quote the manual, "means that both variables end up pointing at the same data, and nothing is copied anywhere".
The only thing that is deprecated with =& is "assigning the result of new by reference" in PHP 5, which might be the source of any confusion. new is automatically assigned by reference, so & is redundant/deprecated in$o = &new C;, but not in $o = &$c;.
Since it's hard to search, note that =& (equals ampersand) is the same as = & (equals space ampersand) and is often written such that it runs into the other variable like $x = &$y['z']; or $x = &$someVar (ampersand dollar sign variable name). Example simplified from the docs:
$a = 3;
$b = &$a;
$a = 4;
print "$b"; // prints 4
Here's a handy link to a detailed section on Assign By Reference in the PHP manual. That page is part of a series on references - it's worth taking a minute to read the whole series.
It's two different operators. = is assignment as you probably know. And & means the variable should be accessed by reference rather than by value.
$x = &$y['z'];
also has the effect of creating $y['z'] if it doesn't exist, and setting it to null.
This prevents error messages that you might have wanted to read. I haven't found documentation on this yet; possibly new in 5.3, for all I know.
The symbol & is used in various ways in PHP to represent operations with "references". The PHP manual has a section titled References Explained which every PHP programmer should read.
It's important to understand that references in PHP are not a data type, like a pointer, but a concept regarding how variables work. There is therefore no single meaning of & - you should not read it as "make a reference" - it just means "something reference-y is happening here".
In particular, the syntax $a =& $b, which can also be written $a = &$b, represents assignment by reference. It binds two variables together, so that they both point at the same piece of data. Think of the & as modifying the = rather than modifying the $b.
Once you've bound two variables together in this way, they are interchangeable - you can't say that "$a points to $b" or "$b points to $a":
$a =& $b;
$a = 42;
// both $a and $b will be 42
$b = 101;
// both $a and $b will be 101
You can also link more than two variables together as references, and again it doesn't matter which of the existing names you use on the right-hand side of the assignment:
$a =& $b;
$c =& $b;
$d =& $a;
$e =& $c;
// $a, $b, $c, $d, and $e now all point to the same data, interchangeably
However, if you put the same variable on the left-hand side, it breaks the existing link of that variable, and links it to something else:
$a =& $b;
// $a and $b are linked together
$a =& $c;
// $a is now linked to $c
// the value of $b doesn't change, but it is not linked to $a or $c
To "break" the link without making a new link, you can use the unset keyword:
$a =& $b;
$c =& $a;
// $a, $b, and $c are all linked together
unset($a);
// $b and $c are still linked together, but $a is independent
Some descriptions refer to =& as "creating or adding to a reference set". Perhaps it would have been better if it had been implemented as a function, like bind($a, $b) to highlight that both arguments are affected by the operation.
I'd like to draw some attention to the semantics and code styling of "Assigning By Reference". The OP's opening sentence hints toward a misconception:
What does the =& (equals-ampersand) assignment operator do in PHP?
First, let's review the dedicated section of the PHP Docs page for Assignment Operators. Notice how the = comes before the & and that the two symbols are separated. This is because they are NOT "combined operators". Semantically, it is "assigning" a "reference"; it is not a "reference assignment operator".
Second, look at how ALL of the "combined operators" are written lower on the docs page. The = is consistently the right-most symbol. This is a very important distinction because writing the & on the left of the = changes the meaning -- it becomes a combined operator ("bitwise and assignment operator") instead of an assignment to a reference.
PSR coding standards should be something that all PHP developers are aware of and strive to obey. Notice this rule of PSR-12 Section 6.2:
All binary arithmetic, comparison, assignment, bitwise, logical, string, and type operators MUST be preceded and followed by at least one space
By this rule, there should always be a space after the = operator -- this makes =& a violation.
Furthermore, there are other rules that state that there should not be a space between & and its variable/argument/function/etc.
When using the reference operator & before an argument, there MUST NOT be a space after it
TL;DR
When assigning a reference, always write the = with spaces on both sides and never write a space after &.
Bad: $a =& $b;
Good: $a = &$b;
Demonstrated consistently/correctly: https://riptutorial.com/php/example/11991/assign-by-reference
Not demonstrated consistently/correctly:
https://www.php.net/manual/en/language.references.whatdo.php#:~:text=$a%20=%26%20$b;
https://www.php.net/manual/en/language.references.whatdo.php#:~:text=$foo%20=%26%20find_var($bar);
https://www.php.net/manual/en/language.oop5.basic.php#:~:text=$reference%20%20=%26%20$instance;
Can someone please explain what the "&" does in the following:
class TEST {
}
$abc =& new TEST();
I know it is by reference. But can someone illustrate why and when I would need such a thing? Or point me to a url where this is explained well. I am unable to grasp the concept.
Thank you very much.
As I understand it, you're not asking about PHP references in general, but about the $foo =& new Bar(); construction idiom.
This is only seen in PHP4 as the usual $foo = new Bar() stores a copy of the object. This generally goes unnoticed unless the class stored a reference to $this in the constructor. When calling a method on the returned object later on, there would be two distinct copies of the object in existence when the intention was probably to have just one.
Consider this code where the constructor stores a reference to $this in a global var
class Bar {
function Bar(){
$GLOBALS['copy']=&$this;
$this->str="hello";
}
}
//store copy of constructed object
$x=new Bar;
$x->str="goodbye";
echo $copy->str."\n"; //hello
echo $x->str."\n"; //goodbye
//store reference to constructed object
$x=&new Bar;
$x->str="au revoir";
echo $copy->str."\n"; //au revoir
echo $x->str."\n"; //au revoir
In the first example, $x and $copy refer to different instances of Foo, but in the second they are the same.
Firstly, you don't really need to use it if you are using PHP 5, in PHP 5 all objects are passed by reference by default.
Secondly, when you assign an object to a variable name, either by creation, passing in a parameter, or setting a variable value, you are either doing so by reference or value.
Passing by reference means you pass the actual memory reference for the object, so say you passed an object as a parameter to a function, any changes that function makes to that variable will be reflected in the parent method as well, you are actually changing the state of that object in memory.
The alternative, to pass by value means you pass a copy of that object, not the memory reference, so any changes you make, will not be reflected in the original.
The PHP Manual does a pretty decent job of explaining references.
I should note, that they are NOT the same thing as a pointer or a reference in many other languages, although there are similarities. And as for objects being "passed by reference" by default - that's not exactly true either.
I would recommend reading the manual section first (and probably then re-reading a couple of times until you get it), and then come back here if you still have more questions.
A simpler way to look at it may be like this:
$a = 'foo';
$b = 'bar';
$a =& $b;
$b = 'foobar';
echo $a . ' ' . $b;
will output
foobar foobar
It might be helpful to think of it like this: In PHP, all variables are really some sort of pointer: The entries in the symbol table - the thing which maps variable names to values - contain a zval * in the C implementation of the Zend Engine.
During assignment - this includes setting function arguments - magic will happen:
If you do $a = $b, a copy of the value pointed to by the symbol table entry of $b will be created and a pointer to this new value will be placed in the symbol table entry for $a. Now, $a and $b will point to different values. PHP uses this as its default calling convention.
If you do $a =& $b, the symbol table entry for $a will be set to the pointer contained in the symbol table entry for $b. This means $a and $b now point to the same value - they are aliases of each other with equal rights until they are rebound by the programmer. Also note that $a is not really a reference to $b - they are both pointers to the same object.
That's why calling them 'aliases' might be a good idea to emphasize the differences to C++' reference implementation:
In C++, a variable containing a value and a reference created from this variable are not equal - that's the reason why there are things like dangling references.
To be clear: There is no thing like a reference type in PHP, as all variables are already internally implemented as pointers and therefore every one of them can act as a reference.
PHP5 objects are still consistent with this description - they are not passed by reference, but a pointer to the object (the manual calls it an 'object identifier' - it might not be implemented as an actual C pointer - I did not check this) is passed by value (meaning copied on assignment as described above).
Check the manual for details on the relation between PHP5 objects and references.