2012-04-04 4 views
12

Considerate questa classe:In che modo PHP evita la ricorsione infinita qui?

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; 
    } 
} 

sto sovraccarico metodo magico __set() di PHP. Ogni volta che imposto una proprietà in un oggetto della classe test, chiameremo __set(), che a sua volta chiama other_set().

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

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

Ma other_set() ha la seguente riga $this->$name = $value. Non dovrebbe questo comportare una chiamata a __set(), causando una ricorsione infinita?

Ho teorizzato che avrebbe chiamato __set() solo quando si impostano le cose al di fuori della classe. Ma se chiami il metodo t() puoi vederlo chiaramente anche attraverso lo __set().

risposta

11

__set is only called once per attempt for a given property name. Se (o qualsiasi cosa esso chiama) tenta di impostare la stessa proprietà, PHP non chiamerà di nuovo __set - verrà semplicemente impostata la proprietà sull'oggetto.

+0

Questo è corretto. Se qualcuno vuole vedere i dettagli dell'implementazione, è in "zend_object_handlers.c". – Confluence

+0

@Confluence: Grazie ... mi stavo chiedendo dove avrei letto quello. :) Impossibile trovarlo nel manuale; Stavo iniziando a chiedermi se l'avessi immaginato. Ma tutti i miei test lo hanno confermato, quindi ... – cHao

+0

Questa risposta è stata così utile! –

2

Dal documentation:

__set() viene eseguito durante la scrittura di dati di inaccessibili proprietà

Ad esempio:

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"; 

In questo caso, $x->prop è inaccessibile e __set sarà chiamato. $x->attributes è anche inaccessibile, pertanto verrà chiamato __set. Tuttavia, $x->bar è accessibile pubblicamente, pertanto __set verrà chiamato non.

Analogamente, nel metodo __set, $this->attribtues è accessibile, quindi non vi è alcuna ricorsione.

Nel codice di esempio sopra riportato, $this->$name è accessibile nell'ambito in cui è chiamato, pertanto non viene chiamato __set.

+0

Che differenza fa? – Confluence

+0

@Confluence la proprietà non è inaccessibile all'interno della classe stessa .. – TZHX

+0

@TZHX Inaccessibile può significare non visibile O non dichiarata. Tutte le proprietà sono inaccessibili per definizione poiché non ho proprietà dichiarate. – Confluence