为何给不存在的对象属性赋值引用时会调用__get()魔术方法?
PHP引用赋值与普通赋值的重载属性行为差异
代码示例1(引用赋值)
class Test { public $prop1; public function __get(string $n) { echo '__GET: '.$n.' - but why?<br>'; die; } } $t = new Test(); $x1 = new \stdClass(); $t->prop2 = &$x1; echo '.'; die;
现象:尝试将stdClass对象的引用赋值给不存在的prop2属性时,__get()方法被执行;若移除die(),会抛出Indirect modification of overloaded property has no effect异常。
代码示例2(普通赋值)
class Test { public $prop1; public function __get(string $n) { echo '__GET: '.$n.' - but why?<br>'; die; } } $t = new Test(); $x1 = new \stdClass(); $t->prop2 = $x1; echo '.'; die;
现象:程序运行正常,不会触发__get()方法。
为什么会出现这种差异?
这得从PHP的属性重载逻辑和引用赋值的底层机制说起:
- 普通赋值的逻辑:当执行
$t->prop2 = $x1时,这是直接对不存在的属性执行赋值操作。PHP默认会自动为$t对象添加prop2这个公共属性,整个过程不会触发__get()(__get()仅在读取不存在/不可访问的属性时才会被调用),所以程序正常运行。 - 引用赋值的逻辑:引用赋值
$t->prop2 = &$x1的本质是要把$x1的引用绑定到$t->prop2这个属性上。这时候PHP需要先找到$t->prop2对应的「变量容器」,但这个属性不存在,于是PHP会调用__get()尝试获取该属性。但__get()返回的是临时值(而非可绑定引用的容器),后续尝试给这个临时值绑定引用时就会失败,进而触发异常——这也是__get()被触发的核心原因。
如果要让引用赋值正常工作,需要在类中定义__set()方法处理不存在的属性赋值,结合类内部数组存储属性来支持引用绑定。
内容的提问来源于stack exchange,提问作者John Smith
相关产品推荐
相关产品推荐

