A few days ago I took a while to debug an issue, and found out the weird behaviour from unset() class vars and magic __set() method.
So here is the thing:
class A {
public $var;
public function unsetVar() {unset($this->var);}
}
class B extends A {
public $attr = array();
public function __set($key, $value) {$this->attr[$key] = $value;}
}
$a = new A();
$a->unsetVar();
$a->var = 'teste';
$b1 = new B();
$b1->var = 'teste';
$b2 = new B();
$b2->unsetVar();
$b2->var = 'teste';
var_dump($a, $b1, $b2);
php online example: http://goo.gl/CO3Uxj
That var_dump() returns:
object(A)#1 (1) {
["var"]=>
string(5) "teste"
}
object(B)#2 (1) {
["attr"]=>
array(1) {
["var"]=>
string(5) "teste"
}
}
So if unset the $a->var then the re-set will work as expected, just to be sure $b1->var will set the var and not triggering the magic method, but when at b2 we unset the var, then the magic method will be triggered not resetting the $b2->var.
Firstly I thought that internally PHP would use the magic method __set() to set the vars that were unset by using reflection or some internal method to check the property exist.
So since I've overridden __set() it would execute mine, but didn't found nothing to support this.
So, does anyone know why it behaves like this? (with some docs to support)
Thanks everyone!
unset($var)
destroys the variable $var
, making it inaccessible, causing a 'undefined variable' notice if you try to use $var
again. To clarify unset()
destroys the variable
, not the value
. and destroying the variable means that it would no longer exist (be accessible).
I couldn't find docs clearly stating this, but the following test supports my claim (as does your test with __set
).
I did the following which demonstrates that __unset()
actually makes variables inaccessible:
class x {
public $var;
}
$x = new x();
echo '<pre>';
print_r(get_object_vars($x)); //prints Array([var] =>)
echo '<br>';
unset($x->var); //prints Array()
print_r(get_object_vars($x));
So, get_object_vars
docs state:
Gets the accessible non-static properties of the given object according to scope.
and __set
, docs state:
is run when writing data to inaccessible properties.
and unset()
, docs state:
destroys the specified variables
From which I conclude 'destroys' = 'make variable inaccessible' because if unset
had done anything other than make it inaccessible, then [var] =>
(or [var] =>NULL
) would have been printed the 2nd time.
To answer your question.
So, does anyone know why it behaves like this? (with some docs to support)
Because it is supposed to. The docs just don't clearly state how it functions on class variables.
Also (docs needed), class variables are references to values, and unsetting a reference destroys just the reference not the value (unless it is the only reference to the value).
Edit: You could possibly report a documentation bug if you're not satisfied with this answer.