Variables and references
In a recent post to the PHP Object Generator mailing list, John asked a question about the significance of the & in front of the $variable name when passing objects into routines in POG.Since this has come up in a few fora that I keep tabs on, as well as in my own coding, I thought that I'd have a go at explaining it.
As with all my thoughts and replies, I reserve the right to be utterly wrong, so caveat lector.
When assigning variables from one place to another, there are two possible meanings behind the assignment. The first, which seems to be the obvious interpretation to the majority of people is that assigning variable A to variable B implicitly means 'take the value stored in variable A and put it into variable B'.
Thus, in php, if we define $a as containing 'abc', then assign $a to $b, we expect that both $a and $b will contain 'abc'. Indeed, with the following php script, that is what we will get.
<?phpproduces:
$a = "abc";
$b = $a;
printf("a is '%s', b is '%s'\n", $a, $b);
?>
a is 'abc', b is 'abc'
An alternative interpretation of the assignment statement, which to many people appears bizarre but which is useful in certain circumstances, is that by assigning $a to $b we might actually be saying 'make variable B refer to the same thing that variable A refers to'. Under this assumption, if we change the value in variable A (or B) after the assignment of $a = $b, then the value that the other variable holds will also change (since they refer to the same thing). Let's try that and see which of our interpretations is correct.
<?phpproduces:
$a = "abc";
$b = $a;
printf("a is '%s', b is '%s'\n", $a, $b);
$a = "xyz";
printf("a is now '%s', b is now '%s'\n", $a, $b);
?>
a is 'abc', b is 'abc'
a is now 'xyz', b is now 'abc'
So, we can see from this that the first interpretation is correct. Variable $a and $b are separate things - once the value has been assigned from one to the other, they exist as independent entities. Now let's look at the & operator in this context by using it to assign to a third variable, $c.
Taking our second script and extending it a bit, we now have the following:
<?phpWhen we run this, it produces:
$a = "abc";
$b = $a;
$c = &$a; // assign a reference to $a into $c
printf("a is '%s', b is '%s', c is '%s'\n", $a, $b, $c);
$a = "xyz";
printf("a is now '%s', b is now '%s',
c is now '%s'\n", $a, $b, $c);
?>
a is 'abc', b is 'abc', c is 'abc'
a is now 'xyz', b is now 'abc', c is now 'xyz'
Hmmm. We assigned $a to $c before we changed the value of $a. Why does $c apparently contain the value that we assigned to $a after the first print statement? Well, the answer is 'Because $c contains a reference to $a'. Effectively it points towards $a and says 'Yeah, what he said!'. Effectively $a and $c are one and the same thing.
So, that's the score with 'ordinary' variables and it holds true for both php4 and php5. Let's see now what happens with objects.
Objects and references
In this next section, I'm going to be assuming the existence of the following php object. It has a public name attribute and - for convenience - it 'knows' how to convert itself into a string.<?php
class testClass {
var $name;
function testClass($name) {
$this->name = $name;
}
function __toString() {
return $this->name;
}
}
?>
Let's try our last script but using this object instead of simple strings.
<?php
$a = new testClass("My object name");
$b = $a;
$c = &$a; // assign a reference to $a into $c
printf("a is '%s', b is '%s', c is '%s'\n", $a, $b, $c);
$a->name = "New Name";
printf("a is now '%s', b is now '%s',
c is now '%s'\n", $a, $b, $c);
?>
Now if we run this, we get one of two possible result. Exactly what you get depends on what version of php you run the code through.
PHP 4
Running the script under php4, we get the following:a is 'My object name', b is 'My object name', c is 'My object name'
a is 'New Name', b is 'My object name', c is 'New Name'
PHP 5
However, under php5 the result is:a is 'My object name', b is 'My object name', c is 'My object name'
a is 'New Name', b is 'New Name', a is 'New Name'
So, what's the reason for the difference? What's going on?
Comparing the two versions, we see that under php4 assigning an object variable to a different variable results in two separate objects. Each can be modified independently which is why in the second print statement $a gives a different answer from $b. Assigning using an explicit reference into $c ($c = &$a) copies a reference into the $c variable so $a and $c can be considered to be the same. Thus simple variables like strings and complex objects behave essentially the same as each other under php4.
Under php5, however, we see different behaviour. Here, even though we assign from $a to $b using a simple assignment statement ($b = $a), because $a is an object we get a reference assignment. This is (apparently) to bring php into line with languages like java. Under php5, the & reference assignment continues to behave as in php4. Thus, there appears to be no way to get php4-like behaviour under php5 as far as objects are concerned.
In fact, if we want to take copies of an object into a different variable such that each is a separate entity under php5, we have to use the clone() function i.e. $b = clone($a).
There now, that hardly hurt at all, did it?