PHP:每次__set函数行为都不同

Der*_*huk 4 php

这样可以在对象上创建新属性.但是,有人可以用支持链接解释为什么setAttrib表现为两种不同的方式吗?为什么不引起......等待它......堆栈溢出!! ??

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);
Run Code Online (Sandbox Code Playgroud)

生产...

setAttrib
__set
setAttrib
object(Test)#1 (1) {
  ["hey"]=>
  string(8) "It works"
}
Run Code Online (Sandbox Code Playgroud)

编辑:我不是在寻找替代方案. 我在寻找这个有效的原因.

Pas*_*TIN 8

您并不是唯一一个注意到非递归行为的人:手册页面上的这条评论指出:

2 - PHP不会递归地从内部调用一个魔术方法(至少相同$name).

并且,稍后在同一页面上,有一个,其中指出:

使用时,递归检测功能可能特别危险 __set.当PHP遇到通常会调用__set但会导致递归的语句时 ,而不是触发警告或者只是不执行语句,它将表现为根本没有__set 定义任何方法.
在这种情况下,默认行为是动态指定的属性添加到对象从而打破所有后续调用所期望的功能,__set或者__get该属性.


并且,在PHP的bugtracker上,有#47215:魔术方法__set()在递归调用时被绕过,它说:

__set()在递归调用时绕过Magic方法.
PHP会自动在实例上创建一个属性,而不是递归调用__set()或者不会抛出递归错误

它已被关闭为:

感谢您抽出宝贵时间给我们写信,但这不是错误.

该错误报告本身指向这篇博文,以这句话结尾(引用,强调我的):

毕竟我认为它可能不是一个bug而是预期的行为,否则我们无法从__set() 方法中定义对象属性.