The PHP language has a couple of quirky behaviours which can catch you out unexpectedly if you don't know what to look for. Here are two I've discovered recently:
1. all variables that contain instantiated objects are references to that object, and explicit "references" actually refer to ... er, the variable (symbol) table, or something ..?
The only way I can explain is by means of example:
<?php
class SimpleClass {
function __construct() {
$this->var = '';
}
}
$instance = new SimpleClass(); //
$assigned = $instance; // copy assignment
$reference =& $instance; // reference assignment
$instance->var = 'asdasd'; // change the field in the original instance
$reference = null; // make the 'reference' variable point to nothing
var_dump($reference); // => NULL, as expected
var_dump($assigned); // => object(SimpleClass)#1 (1) { ["var"] => string(6) "asdasd" }
var_dump($instance); // => NULL
Two things to take away:
$assigned = $instance creates a second variable which refers to the original object; and$reference =& $instance essentially means that $reference is now an alias for $instance, and anything you do to one also happens to the other. I don't know any other language that has these sorts of references.If you change $reference = null to $instance = null the final output is the same. $reference and $instance are the same variable (albeit spelled differently.)
2. foreach maintains a reference to an array, even if you overwrite the array variable inside the loop.
<?php
$foo = array(1,2,3);
foreach ($foo as $x) {
echo $x;
$foo = array(4,5,6);
}
var_dump($foo);
...which outputs:
1
2
3
array(3) {
[0] => int(4)
[1] => int(5)
[2] => int(6)
}
While you're inside the loop, the iterator always refers to the object originally identified by the variable.
For a more potentially destructive example, we can overwrite $foo with something that can't be foreached over:
<?php
$foo = array(1,2,3);
foreach ($foo as $x) {
echo $x;
$foo = $x;
}
var_dump($foo);
...which outputs:
1 2 3 int(3)
And now for something that will hopefully make you cringe:
<?php
$foo = array(1,2,3);
foreach ($foo as $foo) {
echo $foo;
}
var_dump($foo);
Yes, apparently this is valid, even though we're overwriting the array with its own members in a horribly obfuscating and mind-hurting way. The output is:
1 2 3 int(3)
...which I suppose makes sense, once you realise that the foreach loop seems to have created a safe reference to the original $foo array. Note that the second $foo variable doesn't mask or shadow the outer-scope's foo, it overwrites it, just as if you did the assignment inside the loop body.