Today I present to you a PHP puzzler that in fact had me stumped for a day or two. I do enjoy when a language throws a curve ball; it presents an opportunity to gain insight on the mechanics and become acquainted with the nuances of the language in question. After all, better understanding leads to better code.
The Puzzler
//function that adds 1 to the argument
function addOne(&$value) {
++$value;
}
//lets try it out
addOne($variable = 5);
//print the $value now
echo($variable);
And now we vote! What is the output of this example?
- compile error
- emtpy string
- 6
- 5
#1: compile error [FALSE] The code is indeed proper PHP syntax.
#2: empty string [FALSE] PHP variable scoping places variables defined within function calls in the same scope that the function is being called from – $variable is indeed defined and initialized to 5.
#3: 6 [FALSE] Ok so it compiles and the variable is defined as expected, everything should be working nicely, right? We passed it by reference – what’s going on? Did $variable forget that it has been changed?
#4: 5 [CORRECT] Strangely enough, the value of $variable remains set to 5. This can be verified – try running the code snippet at http://codepad.org.
The Spiel
Intuitively, we expect from the code that a variable named ‘variable’ is defined, initialized to 5 and then passed-by-reference to the function call. Perhaps surprisingly, this is not the case with PHP – what is in fact passed is an expression that evaluates to the same value as that of $variable. To protect $variable PHP’s copy-on-write mechanism kicks in when we try to modify this value. $variable did not forget that is was changed; the reference was never to $variable to begin with, but to the anonymous expression. To achieve what was really intended, we must pass a variable instead of an expression to the function.
function addOne(&$value) {
++$value;
}
$variable = 5;
addOne($variable);
echo($variable); //now it will be 6