Has PHP always made copies when using object assignment? - php

For example, I have the following class.
class A {
public $foo = 1;
}
$a = new A;
$b = $a; // a copy of the same identifier (NB)
According to the current PHP docs a copy of the identifier is made, has this always been the case? If not, when did it change?

This wasn't always the case. In PHP4 an object was copied when assigned to a new variable. When PHP5 was introduced this changed to pass a reference of the object being assigned.
(From the manual)
In PHP 5 there is a new Object Model. PHP's handling of objects has been completely rewritten, allowing for better performance and more features. In previous versions of PHP, objects were handled like primitive types (for instance integers and strings). The drawback of this method was that semantically the whole object was copied when a variable was assigned, or passed as a parameter to a method. In the new approach, objects are referenced by handle, and not by value (one can think of a handle as an object's identifier).

Related

What's the point of an ampersand '&' before the 'new' keyword?

Why would you do this?
$a = &new <someclass>();
For example, the documentation for SimpleTest's SimpleBrowser uses this syntax (http://www.simpletest.org/en/browser_documentation.html).
$browser = &new SimpleBrowser();
Is there any use to this? Is this a relic of PHP 4?
Edit:
I understand that the ampersand returns by reference, but what is the point of returning a NEW instance of an object by reference?
In PHP5, objects are passed using opaque object handles. You can still make a reference to a variable holding such a handle and give it another value; this is what the &new construct does in PHP5. It doesn't seem to be particularly useful though – unless you clone it explicitly, there's only ever one copy of a particular object instance, and you can make references to handles to it anytime after instantiation if you want to. So my guess would be the code you found is a holdover from when &new was a necessary pattern.
Since PHP5 new returns references automatically. Using =& is thus meaningless in this context (and if I'm not mistaken giving a E_STRICT message).
Pre-PHP5 the use of =& was to get a reference to the object. If you initialized the object into a variable and then assigned that to a new variable both of the variables operated on the same object, exactly like it is today in PHP5.

What's the point of writing : $foo = & new someClass();?

I am getting a deprecated warning because of a library I am using. The statement is the following :
$this->_ole =& new OLERead();
The thing is I don't see why one would want to use & new in an instantiation.
If I am not mistaken, the & operator tells PHP to copy the reference to the instance, and not the instance itself. But in that case, isn't it pointless to ask for a copy of a reference that isn't stored ?
But since I don't exactly know how new exactly works, maybe this was supposed to save some obscure garbage collection, or something like that.
What do you think about that ?
From the documentation:
As of PHP 5, the new operator returns a reference automatically, so assigning the result of new by reference results in an E_DEPRECATED message in PHP 5.3 and later, and an E_STRICT message in earlier versions.
The library you use was probably developed for PHP 4.
Helpful information about why this was used can also be found in the migration guide:
In PHP 5 there is a new Object Model. PHP's handling of objects has been completely rewritten, allowing for better performance and more features. In previous versions of PHP, objects were handled like primitive types (for instance integers and strings). The drawback of this method was that semantically the whole object was copied when a variable was assigned, or passed as a parameter to a method. In the new approach, objects are referenced by handle, and not by value (one can think of a handle as an object's identifier).
That's an idiom for PHP4 compatibility. Objects were passed as copies per default there, and this is a workaround to always have references to an instance.
In PHP4, new returned a value and not a reference.
This is not the case in PHP5.
If you write $this->_old =& new OLERead(); a changement of _ole in any object will updates all references to the new object.
This is not the case without & .
EDIT: And yes, in previous versions of PHP, object were passed by copy. At the end, this is quite hard to have a consistent behaviour accross versions.

Is there ambiguity in the way "reference" is used?

For example, in PHP we can write something like this:
class C {
var $x;
function __construct($x) {
$this->x = $x;
}
function __toString() {
return (string)$this->x;
}
}
function f1($obj) {
$obj->x = 2;
}
$a = new C(1);
f1($a);
echo $a; // 2
And some would say that this indicates objects are passed by reference, because you can modify their properties and those changes are reflected outside of the class. i.e., the object is not copied the way primitives are.
But then we can write this:
function f2($obj) {
$obj = new C(2);
}
$b = new C(1);
f2($b);
echo $b; // 1
Which now suggests the object is not passed by reference at all. In reality, the object is copied (i.e., passed by value) but not deep-copied; $obj is copied, but $x still refers to the same thing.
I've heard the word "reference" used to mean both ways; some would say PHP is pass by reference, others would say pass by value.
If we say that PHP is pass by reference, then what do we mean when say define a function like
function f3(&$obj)
? That function takes a reference an to an object, this suggests the first meaning is wrong.
But then what about languages like C++, and structs in C#? My C++ is a bit rusty, but I believe the whole class actually gets deep-copied when pass it around, which is why it's encouraged to make your functions take references if possible, or use pointers. In C# there's a difference between structs and classes in how they get passed.
What do you call this deep-copying behaviour, if not pass by value?
It seems we have 3 behaviours and only two phrases to describe them, and this is creating a lot of confusion in the community.
Heck, I'm just waiting for one of you to tell me I wrote something wrong here.
In summary, the 3 behaviours are:
Objects are deep-copied (the object and its properties are cloned)
Only the object is copied (its properties still refer to the same chunk of memory)
The object is not copied at all
Technically, what should we call each of these behaviours? pass-by-???
First things first: You might want to read References Explained.
Normally, variables are always passed by value. What matters is what the value actually is.
If the variable "holds an object", it holds a reference to the object.
Thus, when you have a function definition like
function foo($bar) {}
a reference to the object is passed. That is why you can change the object.
But if you assign a new value to the variable inside the function, then you are just overwriting the reference with something else and you loose the reference to the object.
So assuming you have a variable $someVar that you pass to the function, $bar and $someVar will have the same value (namely a reference), but they have their own location in memory.
Before:
$someVar -> object_reference ┐
├ -> object
$bar -> object_reference ┘
After:
$someVar -> object_reference -> object
$bar -> other_value
Now, if the function definition is like
function foo(&$bar) {}
then you are actually passed a reference to the location in memory of some other variable.
If you call the function with foo($someVar), $bar will point to the same location as $someVar, i.e. if you assign a new value, you are overwriting that particular location in the memory.
Before:
$someVar ┐
├ -> object_reference -> object
$bar ┘
After:
$someVar ┐
├ -> other_value object
$bar ┘
If I had my druthers, the term "object reference" in .net would be replaced by something like "object-id", to make clear that in most cases when an object is passed to a routine, the object-id is passed by value (though there are some cases, like Dictionary.TryGetValue, where an object-id is passed by reference). Using the same term to describe an object-id and a type of parameter passing leads to confusion.
In C++, the first two are both called pass-by-value. How deep a deep copy occurs depends on the copy semantics of the class in question, which can and should be specified by the programmer (some classes are handles to resources and must be shallow-copied; others, such as most containers, must be deep-copied). Python has library functions for deep and shallow copying. Deep copying is sometimes called cloning, esp. in C++ and Java.
The third is called pass by reference. This is the general term for passing something that can be modified in-place by the callee.
(C is an exception to this convention, since it has no notion of reference, but pass-by-pointer is almost the same as pass-by-reference.)
There are two things you have to differentiate... references to variables and references to objects. As long as you don't assign an other value to the parameter $obj, you are dealing with the exact same object as outside of the function. After assigning an other object to it, the variable has changed but since you only passed a reference to the object and not one to the variable, the variable on the outside is still untouched pointing to your original object...

what does "&" mean in front of classes in php?

I've just inherited this code in PHP which seems to do some kind of web service call to googles api. I'm not quite an expert on PHP and there is a few syntax questions I have specifically relating to the following line
$soapClients = &APIlityClients::getClients();
I understand the double "::" as indicating that APIlityClients is a static class but I'm not sure what the "&" in front of APIlityClients means.
When you use an ampersand in front of a variable in PHP, you're creating a reference to that variable.
$foo = 'bar';
$baz = &$foo;
echo $foo //bar
echo $baz //bar
$foo = 'foobazbar';
echo $foo //foobazbar
echo $baz //foobazbar
Prior to PHP5, when you created an object from a class in PHP, that object would be passed into other variables by value. The object was NOT a reference, as is standard in most other object oriented (Java, C#, etc.) languages.
However, by instantiating a class with an ampersand in front of it, you could create a reference to the returned object, and it would behave like an object in other languages. This was a common technique prior to PHP5 to achieve OOP like effects and/or improve performance.
It is PHP's version of getting a reference to something rather than copying its value. So in this case the & would retrieve a reference to the return value of APIlityClients::getClients() rather than a copy of the return value itself.
It means "address of" - and it's referring to the value returned from the getClients() call, not the APllityClients class itself.
Basicly it's saying to assign $soapClients to a reference to whatever is returned from getClients() rather than making a copy of the returned value.
& indicates a pass by reference rather than by value. It doesn't apply much in PHP5 since classes are passed by reference by default in that version, but weren't in previous versions.
the & means it's a reference. References are used to allow multiple variables point to the same object.
this page explains it better than I can though
Also see http://us3.php.net/manual/en/language.references.php for more information on references in php in general

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