2012-04-04 2 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; 
    } 
} 

Я перегружая магический __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

+0

@Confluence: Спасибо ... мне было интересно, где я это прочитал. :) Не удалось найти его в руководстве; Я начинал задаваться вопросом, не подумал ли я об этом. Но все мои тесты подтвердили это, поэтому ... – cHao

+0

Этот ответ был так полезен! –

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

+0

@Confluence свойство не является недоступным из самого класса. – TZHX

+0

@TZHX Недостижимый может означать, что он не отображается или не объявлен. Все свойства недоступны по определению, так как у меня нет объявленных свойств. – Confluence

Смежные вопросы