This manages to create a new property on the object. But, can someone explain, with supporting links, why setAttrib
behaves in two different ways? Why doesn't it cause a... wait for it... stack overflow!!??
class Test
{
public function setAttrib( $key, $value ) {
echo "setAttrib\n";
// first time: calls $this->__set($key, $value)
// second time: just sets a public property (but, when exactly was it created?)
$this->$key = $value;
}
public function __set( $key, $value ) {
echo "__set\n";
$this->setAttrib($key, $value);
}
}
$test = new Test();
$test->setAttrib('hey', 'It works');
var_dump($test);
produces...
setAttrib
__set
setAttrib
object(Test)#1 (1) {
["hey"]=>
string(8) "It works"
}
Edit: I'm not looking for an alternative. I'm looking for the reason why this works.
You are not the only one who seems to have notice that non-recursive behaviour : this comment on the manual's page states :
2 - PHP will not recursively call one magic method from within itself (at least for the same
$name
).
And, a bit later on the same page, there is this one, which states :
The recursion detection feature can prove especially perilous when using
__set
. When PHP comes across a statement that would usually call__set
but would lead to recursion, rather than firing off a warning or simply not executing the statement it will act as though there is no__set
method defined at all.
The default behaviour in this instance is to dynamically add the specified property to the object thus breaking the desired functionality of all further calls to__set
or__get
for that property.
And, on PHP's bugtracker, there is #47215 : magic method __set() is bypassed on recursive call, which says :
Magic method
__set()
is bypassed on recursive call.
PHP automatically creates a property on instance instead of recursively calling__set()
or instead of throwing a recursivity error
And it has been closed as :
Thank you for taking the time to write to us, but this is not a bug.
That bug-report, itself, points to this blog-post, which ends by this sentence (quoting, emphasis mine) :
After all I think it may not be a bug but expected behaviour, otherwise we could not be able to define object properties from within
__set()
method.
__set is only used when writing to inaccessible properties. That is, those who are not accessible (private or protected) or those that aren't set at all. Therefore, __set will only be called once.
Here's what happens:
See user comments for http://php.net/__set for proof that __set can't recurse.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With