2011-02-08 15 views
9

Większość zasobów w PHP nigdy nie dotyczy zarządzania pamięcią, ponieważ sam język jest całkiem niezły w robieniu tego za ciebie. Jednak w PHP często kończy się praca z zewnętrznymi zasobami, które nie są pamięcią - obsługa baz danych, sesje, transakcje bazy danych itp. Te zewnętrzne zasoby mogą być zarządzane najczystrzej z wykorzystaniem pewnej formy obiektu RAII.Czy PHP obsługuje wzorzec RAII? W jaki sposób?

Początkowo sądziłem, że PHP używał schematu zbierania śmieci podobnego do JVM lub CLR, gdzie pojęcie destruktora nie istnieje. (Pamiętaj: Everyone thinks about garbage collection the wrong way - finalizatory nie są destruktorami!) Istnieje specjalna metoda __destruct, ale myślałem, że był to "finalizator" podobny do finalizatora Java lub C#. Z tego powodu nie można używać RAII na maszynie JVM lub CLR (bloki C# 'using dostarczają ci około 95% drogi, ale to trochę inaczej ...).

Jednak, Google seems to indicate that PHP supports the RAII pattern, chociaż nie mogę znaleźć potwierdzenia tego w dokumentach PHP. Czy język obsługuje to i czy umieszczenie logiki porządkowania w wystarczającej ilości wystarcza do wykonania zadań RAI?

Odpowiedz

9

To prawie to samo pytanie, co Is destructor in PHP predictable?, a odpowiedź jest taka sama. PHP używa przeliczania i obiecuje, że destruktor zostanie wywołany natychmiast, jak tylko refcount przejdzie do zera (zazwyczaj gdy obiekt wykracza poza zakres). Więc jeśli tworzysz obiekt i uważaj, aby nie wyciekł poza zakres, RAII jest wykonalny.

+3

Kolejna uwaga: gdy wiele obiektów opuścić zakres w tym samym czasie, kolejność ich destruktory są nazywane oficjalnie zdefiniowana, a zazwyczaj w FIFO kolejności (dokładnie przeciwieństwo tego, co jest potrzebne do właściwego RAII). To przełom w mojej szczególnej sprawie użycia. – Brilliand

+0

@Brilliand możesz sztucznie dodawać nawiasy klamrowe, aby wymusić zamawianie? :) – hobbs

+0

Aparat ortodontyczny tego nie zrobi - tylko funkcja może wprowadzić nowy zakres. Nadal możliwe, ale to może oznaczać wiele elementów. – Brilliand

4

PHP używa licznika odwołań, więc gdy skończysz ze zmienną, natychmiast zostanie wyczyszczona. (O ile nie tworzysz cykli.) To pozwala na szybkie zwalnianie zasobów, więc nie musisz się martwić o jawne zarządzanie zasobami, nie będąc ostrożnym, aby nie tworzyć cykli pamięci.

Jeśli chcesz zaimplementować jakąś strategię, możesz to zrobić, upewniając się, że zasób jest używany tylko przez jedną zmienną. Kiedy tylko ta zmienna jest odsunięta od zasobu, należy natychmiast zwolnić zasób.

2

Następująca klasa ReturnHandler zapewnia automatyczne wywoływanie programu obsługi, gdy instancja ReturnHandler wykracza poza zakres. Możesz mieć kilka return s w swojej funkcji (myfunc) bez potrzeby wymyślania uwolnienia zasobu przed każdym z nich.

/** 
* Automatically calls a handler before returning from a function. Usage: 
* 
* function myfunc() 
* { 
* $resource = new Resource(); 
* $rh = new ReturnHandler(function() use ($resource) { $resource->release(); }); 
* // ... 
* if(...) { 
* return; // look, ma, automatic clean up! 
* } 
* } 
*/ 
class ReturnHandler 
{ 
    private $return_handler; 

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

    public function __destruct() 
    { 
    $handler = $this->return_handler; 
    $handler(); 
    } 
} 

Oto test dla niego:

class ReturnHandlerTest extends PHPUnit_Framework_TestCase 
{ 

    private static function trigger_return_handler(&$var) 
    { 
    $rh = new ReturnHandler(function() use (&$var) { $var++; }); 
    } 

    public function test() 
    { 
    $a = 0; 
    $this->assertEquals(0, $a); 
    self::trigger_return_handler($a); 
    $this->assertEquals(1, $a); 
    } 
} 
+0

Wolałabym mieć typ, który opakowuje dany zasób dla większości zastosowań. Ale będzie to działać jako szybkie i brudne rozwiązanie, np. jeśli masz tylko jedną instancję danego zasobu używanego w twoim programie. –

Powiązane problemy