2012-12-12 8 views
7

Mam kod PHP, który wygląda tak:

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

Ale jest problem: ja absolutnie potrzebne destruktor B nazywać przed za destructor. Wydaje się to rozsądne, jak widać. Obiekt B nie potrzebuje żadnego A, więc nie powinno być problemu.

Jednak od czasu wydania 5.4.0 .pc, zamknięcia wydają się automatycznie przechwytywać niejawnie $ this. Dlatego funkcja lambda przekazywana do B i przechowywana przez B zawiera odniesienie do A.

Co oznacza, że ​​A zawiera wskaźnik do B, a B zawiera wskaźnik do A (przez zamknięcie). W tej sytuacji dokumentacja PHP mówi, że destruktory są wywoływane tylko podczas zbierania śmieci i w losowej kolejności. I zgadnij co: destruktor B jest zawsze wywoływany przed A.

Czy istnieje sposób na rozwiązanie tego problemu w elegancki sposób?

+0

nie "wydawać" - definitywnie, jak wskazano w dzienniku funkcji anon func: http://php.net/manual/en/functions.anonymous.php –

+0

Najbardziej eleganckim sposobem, jaki mogę wymyślić, jest zmiana kodu, dzięki czemu nie są zależne od kolejności destruktora. Poleganie na określonej kolejności, takiej jak ta, może wpędzić cię w kłopoty. – RonaldBarzell

+0

Nie mam PHP 5.4 gdzie jestem, więc nie mogę przetestować, ale spróbuj użyć 'create_function'. Możesz również skorzystać z klasy 'Closure' lub po prostu zmienić to, do czego funkcja jest przypisana (nie tak anonimowa, jak wymagałoby to przypisania). –

Odpowiedz

4

Dzięki Pigułkom Eksplozyjnym znalazłem rozwiązanie w klasie Closure.

Można faktycznie zmienić $this przechowywane wewnątrz zamknięcia, tak:

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

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

pamiętać, że nie może tego zrobić, albo dostaniesz błąd składni:

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

D'oh .. to mój przedstawiciel! –

+0

Drzemka, tracisz! –

Powiązane problemy