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

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...

Related

Has PHP always made copies when using object assignment?

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).

Passing by reference - how does it work and why is it used?

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.

Help me understand PHP variable references and scope

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'

Passing object element to class not as a string (like constant) in php?

How can I dynamically pass "items" to class function?
For example here it is a piece of some class and its function where I declare an element of object (items) as $b:
//..........
public function __add2SomeObj($b) {
$namespc = $this -> __someObj(); // __someObj() returns object
$namespc -> cats = $b;
}
//...................
Can I pass any other name instead cats dynamically so it won't be declared as a string?
i.e. something like:
//..........
public function __add2SomeObj($a,$b) {
$namespc = $this -> __someObj(); // __someObj() returns object
$namespc -> $a = $b;
}
//...................
} //end of class started above
$t=new aboveClass()
$t->__add2SomeObj("cats", array(1=>"PussyCat",2=>"Scratchy"));
$t->__add2SomeObj("dogs", array(1=>"Waffy",2=>"Sharik")); // once again but dogs...
Should I define a constant or what to make this or should i declare this protected varibale as object like (object) $vaaar?
Sorry I'm a little bit infamiliar with PHP OOP...
Yes you can do this. Read about variable variables:
Class properties may also be accessed using variable property names. The variable property name will be resolved within the scope from which the call is made. For instance, if you have an expression such as $foo->$bar, then the local scope will be examined for $bar and its value will be used as the name of the property of $foo. This is also true if $bar is an array access.
However you must be carful when dealing with arrays:
$namespc->$a[0]
will get the first element from the array that gets returned by $namespc->$a.
Whereas
$namespc->{$a[0]}
will first resolve $a[0], i.e. get the first value of the array $a, and use this as property name.
What you're asking is whether you can decide at runtime which property to change inside __add2SomeObj as you in the second listing. You can, and you did is correct.
However, properties must be strings __add2SomeObj, so you should ensure that the $a parameter is a string (it will be automatically converted to a string, but this may give unexpected results if $a is an object or an array).
Second, you're allowing the caller too change an arbitrary property. This may or may not violate the encapsulation of your class depending on the class __someObj returns and on the class of __add2SomeObj. It will also create a dynamic property on the object $namespce (i.e., one that does not exist in all the objects of that class), which you may not want.
Finally, and has a consequence of the point before, __add2SomeObj may generate a fatal error. So I'd say you'd better validate the $a paramater against a set of permitted property names.
You syntax is correct:
$obj->cats = $b;
and
$a = 'cats';
$obj->$a = $b;
will do the same thing.
As for whether or not to make "cats" a constant, that's up to you. I would suggest putting the error reporting up:
error_reporting(E_ALL | E_STRICT);
That way if you accidentally put in "cast" and that's not a valid member you'll get an error thrown.
Lastly, PHP is a dynamic language. I get the feeling your background might be with more static languages. This is just something you need to get comfortable with and you need to find a balance between readability and verbosity. But whatever you do, don't try and recreate non-PHP idioms in PHP, which is a common mistake for people coming from one language to another.

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