2012-04-04 131 views
12

考虑这个类:PHP在这里如何避免无限递归?

class test 
{ 
    public function __set($n, $v) 
    { 
     echo "__set() called\n"; 
     $this->other_set($n, $v, true); 
    } 

    public function other_set($name, $value) 
    { 
     echo "other_set() called\n";  
     $this->$name = $value; 
    } 

    public function t() 
    { 
     $this->t = true; 
    } 
} 

我重载PHP的魔术__set()方法。无论何时我在test类的对象中设置属性,它都会调用__set(),然后调用other_set()

$obj = new test; 
$test->prop = 10; 

/* prints the following */ 
__set() called 
other_set() called 

other_set()有以下行$this->$name = $value。不应该导致对__set()的调用,导致无限递归?

我推理说只有在课外设置时才会调用__set()。但如果你打电话给方法t(),你可以看到它也清楚地通过__set()

回答

11

__set is only called once per attempt for a given property name.如果它(或任何它调用的)试图设置相同的属性,PHP将不会再调用__set - 它只会设置对象的属性。

+0

这是正确的。如果有人想看到实现细节,它在'zend_object_handlers.c'中。 – Confluence 2012-04-04 20:14:44

+0

@Confluence:谢谢......我想知道我在哪里阅读。 :)在手册中找不到它;我开始怀疑我是否想象它。但所有的测试证实了它,所以... – cHao 2012-04-04 20:38:11

+0

这个答案很有用! – 2014-08-18 21:25:57

2

documentation

__set()写入数据时难以接近性质

例如运行:

class foo { 
    private $attributes; 
    public $bar; 

    public function __construct() { 
    $this->attributes = array(); 
    } 

    public function __set($n, $v) { 
    echo "__set() called\n"; 
    $this->attributes[$n] = $v; 
    } 
} 

$x = new foo; 
$x->prop = "value"; 
$x->attributes = "value"; 
$x->bar = "hello world"; 

在这种情况下,$x->prop是不可访问和__set将被调用。 $x->attributes也无法访问,因此__set将被调用。然而,$x->bar是公开访问的,因此__set将会调用而不是

同样,在__set方法中,$this->attribtues是可访问的,所以没有递归。

在上面的示例代码中,$this->$name可在其调用范围内访问,因此__set未被调用。

+0

这有什么不同? – Confluence 2012-04-04 19:20:22

+0

@Confluence属性不能从类内部无法访问.. – TZHX 2012-04-04 19:26:43

+0

@TZHX不可访问可能意味着不可见或未声明。由于我没有声明属性,因此所有属性都无法通过定义访问。 – Confluence 2012-04-04 19:28:07