2012-12-12 9 views
7

Ho un codice PHP che assomiglia a questo:

class A { 
    public function __construct() { 
     $this->b = new B(function($x) { return $x + 1; }); 
    } 
}; 

class B { 
    public function __construct($dataProcessingFunction) { 
     $this->dataProcessingFunction = $dataProcessingFunction; 
    } 

    public function processData($data) { 
     $f = $this->dataProcessingFunction; 
     return $f($data); 
    } 
}; 

Ma c'è un problema: ho assolutamente bisogno distruttore di B ad essere chiamato prima di distruttore di A. Questo sembra ragionevole, come puoi vedere. L'oggetto B non ha bisogno di A, quindi non ci dovrebbero essere problemi.

Ma dal momento che PHP 5.4.0, le chiusure sembrano automaticamente catturare implicitamente $ questo. Pertanto, la funzione lambda passata a B e memorizzata da B contiene un riferimento a A.

Ciò significa che A contiene un puntatore a B e B contiene un puntatore a A (attraverso la chiusura). In questo tipo di situazione, la documentazione di PHP dice che i distruttori vengono chiamati solo sulla garbage collection e in un ordine casuale. E indovina un po ': il distruttore di B viene sempre chiamato prima di A's.

C'è un modo per risolvere questo in modo elegante?

+0

non "sembra" - sicuramente, come sottolineato nel anon func changelog: http://php.net/manual/en/functions.anonymous.php –

+0

Il modo più elegante che posso pensare sarebbe quello di alterare il tuo codice in modo da non dipendono da un ordine di distruttore. Affidarsi a un ordine specifico come questo potrebbe metterti nei guai. – RonaldBarzell

+0

Non ho PHP 5.4 dove sono così non posso testare, ma prova a usare 'create_function'. Potresti anche essere in grado di usare la classe 'Closure', o semplicemente cambiare a cosa è legata la funzione (non così anonima che richiederebbe un incarico, penso). –

risposta

4

Grazie a Explosion Pills, ho trovato la soluzione nella classe Closure.

È possibile infatti cambiare il $this memorizzati all'interno della chiusura, in questo modo:

$cb = function($x) { return $x + 1; }; 
$cb = $cb->bindTo(null); 

// now $cb doesn't contain a pointer to $this anymore 

Si noti che non si può fare questo, o si otterrà un errore di sintassi:

// syntax error 
$cb = (function($x) { return $x + 1; })->bindTo(null); 
+0

D'oh .. questo è il mio rappresentante! –

+0

Snooze perdi! –

Problemi correlati