The object assignment doesn't make sense in PHP OOP - php

I was tested and I got this wrong but this doesn't make sense:
class myClass
{
public $x;
function myMethod()
{
echo $this->x;
}
}
$a = new myClass();
$a->x = 10;
$b = $a;
$b->x = 20;
$c = clone $b;
$c->x = 30;
$a->myMethod();
$b->myMethod();
$c->myMethod();
My intuition would be 102030 but the result is actually 202030!!! What happened to 10?!?! Shouldn't the variable of $a be left alone? I thought all objects are independent and would not be updated unless it has direct reference set by the ampersand (=&)?

In $b = $a;, only the object reference is being copied, not the object.
When you use clone, however, the object is indeed being copied, so $c = clone $b, creates both a new object (referenced by $c) and a new reference ($c).
In $b =& $a;, both symbols $a and $b would point to the same reference, that is, not even the reference would be copied (and therefore an assignment to $b of, say, an integer, would also affect the value of $a).
To sum up, there are two indirections here: from the symbol to the "zval" (in the case an object reference) and from the object reference to the object itself (i.e., to a portion of memory where the actual object state is stored).

From the PHP manual:
When assigning an already created instance of a class to a new variable, the new variable will access the same instance as the object that was assigned. This behaviour is the same when passing instances to a function. A copy of an already created object can be made by cloning it.

PHP uses references for objects. So when you create a new one
$a = new myClass();
PHP doesn't actually store it in $a, it just puts the reference there. Now you copy the reference:
$b = $a;
When you modify the object pointed by $a, you also modify the one pointed by $b because they point to the same thing.

As $a represents a reference to an object and not the object itself, you are assigning the reference to $b. Now, $a and $b reference the same object, when you manipulate the object referenced by $b, the changes get reflected accessing it via $a as well.

Objects are handled by reference, and references are aliases on assignment. So after you say $b = $a, both variables refer to the same object.
The value/reference distinction is fundamental in many "modern" OO languages: values are copied, references are aliased. It is perhaps unfortunate that the syntax of the language does not always make it obvious which semantics the variable obeys at any given point.

Related

What exactly are the entities 'Object', 'Object Reference', 'Object Identifier', 'Object Accessors' in PHP? How they function?

Below is the text from PHP Manual :
PHP treats objects in the same way as references or handles, meaning
that each variable contains an object reference rather than a copy of
the entire object.
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.
After going through the above text I've following doubts in my mind:
What exactly the 'Object' is?
What exactly the 'Object Reference' is?
What exactly an 'Object Identifier' is?
Does the entity called 'Object Identifier' work implicitly/internally?
How to create a copy of the 'Object Identifier'?
Do the terms 'Object Reference' and 'Object Identifier' mean the same thing?
What exactly the 'Object Accessors' are?
Do the terms 'Instance of a class', 'Instance of an object', 'Object variable', 'Class instance', 'Object instance' mean the same thing? If yes, what these entities indicate? If no, what are the differences in between their meanings?
How all of the above entities function?
Can someone please clear the doubts I have in an easy to understand, simple and lucid language in short and step-by-step manner?
It would be great if someone can explain these concepts with some suitable, working code example having explanatory comments at appropriate places in the code.
If possible, someone can also explain with the help of pictorial representation of working of these concepts. It would be highly appreciated.
You can take up following example or specify your own suitable example to explain all of the above concepts.
<?php
class A {
public $foo = 1;
}
$a = new A;
$b = $a;
$b->foo = 2;
echo $a->foo."\n";
$c = new A;
$d = &$c;
$d->foo = 2;
echo $c->foo."\n";
$e = new A;
function foo($obj) {
$obj->foo = 2;
}
foo($e);
echo $e->foo."\n";
?>
Thank You.
Reference links from the PHP Manual :
https://secure.php.net/manual/en/oop5.intro.php#oop5.intro
https://secure.php.net/manual/en/language.oop5.references.php#language.oop5.references
An Object is an instance of a class that you create with new Classname.
An Object Reference is a PHP variable whose value is an Object.
An Object Identifier is a value internal to the PHP implementation that identifies a particular object. It's probably something like an index into an array that contains pointers to all the objects.
Yes, they're internal, not visible to PHP applications.
Assign a variable containing an object to another variable. Internally, both variables contain copies of the object identifier.
They're not the same thing, but closely related. An object reference is a PHP variable, the object identifier is the internal data that it contains.
Object accessors are operations that access the contents of objects, such as $d->foo.
Yes, they're all essentially synonyms.
This is all just implementation details for how you can have multiple variables referring to the same object without having to use reference variables explicitly.
$a = new A;
$b = $a;
$a->foo = 2;
echo $b->foo; // echoes 2
The assignment isn't making a copy of the object, it's just copying the object identifier. All copies of an object identifier refer to the same object. Think of it like a pointer in languages like C or C++ -- when you copy a pointer, both variables refer to the same memory.
To make a copy of an object, you have to use clone.
$c = clone $a;
This is different from how arrays work, which is that assignment makes a copy, unless you use an explicit reference variable. (As an optimization, PHP uses copy-on-write, so it doesn't actually copy the array memory unless you modify it.)
$x = array(1);
$y = $x;
$z = &$x;
$x[0] = 2;
echo $y[0]; // echoes 1
echo $z[0]; // echoes 2

In PHP can someone explain cloning vs pointer reference?

To begin with, I understand programming and objects, but the following doesn't make much sense to me in PHP.
In PHP we use the & operator to retrieve a reference to a variable. I understand a reference as being a way to refer to the same 'thing' with a different variable. If I say for example
$b = 1;
$a =& $b;
$a = 3;
echo $b;
will output 3 because changes made to $a are the same as changes made to $b. Conversely:
$b = 1;
$a = $b;
$a = 3;
echo $b;
should output 1.
If this is the case, why is the clone keyword necessary? It seems to me that if I set
$obj_a = $obj_b then changes made to $obj_a should not affect $obj_b,
conversely $obj_a =& $obj_b should be pointing to the same object so changes made to $obj_a affect $obj_b.
However it seems in PHP that certain operations on $obj_a DO affect $obj_b even if assigned without the reference operator ($obj_a = $obj_b). This caused a frustrating problem for me today while working with DateTime objects that I eventually fixed by doing basically:
$obj_a = clone $obj_b
But most of the php code I write doesn't seem to require explicit cloning like in this case and works just fine without it. What's going on here? And why does PHP have to be so clunky??
Basically, there are two ways variables work in PHP...
For everything except objects:
Assignment is by value (meaning a copy occurs if you do $a = $b.
Reference can be achieved by doing $a = &$b (Note the reference operator operates upon the variable, not the assignment operator, since you can use it in other places)...
Copies use a copy-on-write tehnique. So if you do $a = $b, there is no memory copy of the variable. But if you then do $a = 5;, the memory is copied then and overwritten.
For objects:
Assignment is by object reference. It's not really the same as normal variable by reference (I'll explain why later).
Copy by value can be achieved by doing $a = clone $b.
Reference can be achieved by doing $a = &$b, but beware that this has nothing to do with the object. You're binding the $a variable to the $b variable. It doesn't matter if it's an object or not.
So, why is assignment for objects not really reference? What happens if you do:
$a = new stdclass();
$b = $a;
$a = 4;
What's $b? Well, it's stdclass... That's because it's not writing a reference to the variable, but to the object...
$a = new stdclass();
$a->foo = 'bar';
$b = $a;
$b->foo = 'baz';
What's $a->foo? It's baz. That's because when you did $b = $a, you are telling PHP to use the same object instance (hence the object reference). Note that $a and $b are not the same variable, but they do both reference the same object.
One way of thinking about it, is to think of all variables which store an object as storing the pointer to that object. So the object lives somewhere else. When you assign $a = $b where $b is an object, all you're doing is copying that pointer. The actual variables are still disjoint. But when you do $a = &$b, you're storing a pointer to $b inside of $a. Now, when you manipulate $a it cascades the pointer chain to the base object. When you use the clone operator, you're telling PHP to copy the existing object, and create a new one with the same state... So clone really just does a by-value copy of the varaible...
So if you noticed, I said the object is not stored in an actual variable. It's stored somewhere else and nothing but a pointer is stored in the variable. So this means that you can have (and often do have) multiple variables pointing to the same instance. For this reason, the internal object representation contains a refcount (Simply a count of the number of variables pointing to it). When an object's refcount drops to 0 (meaning that all the variables pointing to it either go out of scope, or are changed to somethign else) it is garbaged collected (as it is no longer accessable)...
You can read more on references and PHP in the docs...
Disclaimer: Some of this may be oversimplification or blurring of certain concepts. I intended this only to be a guide to how they work, and not an exact breakdown of what goes on internally...
Edit: Oh, and as for this being "clunky", I don't think it is. I think it is really useful. Otherwise you'd have variable references being passed around all over the place. And that can yield some really interesting bugs when a variable in one part of an application affects another variable in another part of the app. And not because it's passed, but because a reference was made somewhere along the line.
In general, I don't use variable references that much. It's rare that I find an honest need for them. But I do use object references all the time. I use them so much, that I'm happy that they are the default. Otherwise I'd need to write some operator (since & denotes a variable reference, there'd need to be another to denote an object reference). And considering that I rarely use clone, I'd say that 99.9% of use cases should use object references (so make the operator be used for the lower frequency cases)...
JMHO
I've also created a video explaining these differences. Check it out on YouTube.
In Short:
In PHP 5+ objects are passed by reference. In PHP 4 they are passed by value (that's why it had runtime pass by reference, which became deprecated). So, you have to use the clone operator in PHP5 to copy objects:
$objectB = clone $objectA;
Also note that it's just objects that are passed by reference, not other variables. The following may clear you up more:
PHP References
PHP Object Cloning
PHP Objects and References
i've written a presentation to explain better how php manage memory with its variables:
https://docs.google.com/presentation/d/1HAIdvSqK0owrU-uUMjwMWSD80H-2IblTlacVcBs2b0k/pub?start=false&loop=false&delayms=3000
take a look ;)

PHP Reference behavior in VARIABLES and CLASSES (that are formed by reference)- are they different or the same?

In PHP, reference variables modify both when 1 or the other is changed.
New classes are formed by implicit references, but modifying the extension does not modify the parent.
Is this by PHP's design, or are they different kinds of "references?"
You are confusing subclassing (extending) with references.
This is extending, which is what you described:
class ParentClass{ };
class ChildClass extends ParentClass { };
$parent = new ParentClass;
$child = new ChildClass;
$parent->setName('Dad');
$child->setName('Daughter');
echo $parent->name;
// Dad
Is that, in fact, what you wanted to be describing?
Passing variables/classes by reference is a completely different conversation and isn't really connected to the idea of subclassing/extending a class. It works more like this.
$parent = new ParentClass;
$child = new ChildClass;
$childRef = $child; // $childRef isn't a copy, it's a reference to $child.
$childRef->setName('Daughter');
echo $child->name;
// Daughter
// Notice that it's the same as if you had called setName( ) on $child itself;
References in PHP are a weird construct. $a =& $b; makes $a a reference to $b. This means that whenever the value of $b changes, $a will reflect that change. Or put differently, $a will always have the same value as $b.
In PHP 4, objects would be implicitly cloned when assigning them. Eg. if $b is an object, the code $a = $b would create a new object, which is a copy of $b, and assign it to $a. This is rather a problem, since you usually want reference semantics on objects. To get around this, you had to use references when dealing with objects. Since PHP 5 this has changed, so today there are very few cases (if any) where you should use references.

Reference assignment operator in PHP, =&

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;

Php By Reference

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.

Categories