Большинство ресурсов на PHP никогда не касаются управления памятью, потому что сам язык довольно хорош для этого. Однако в PHP вы часто сталкиваетесь с внешними ресурсами, которые не являются обработкой базы данных, сеансами, транзакциями базы данных и т. Д. Эти внешние ресурсы можно было бы наиболее эффективно использовать с использованием какой-либо формы объекта RAII.
Первоначально я думал, что PHP использует схему сбора мусора, похожую на JVM или CLR, где концепция деструктора не существует. (Помните: каждый думает о сборке мусора неправильным образом – финализаторы не являются деструкторами!) Существует специальный метод __destruct
, но я думал, что это «финализатор», похожий на финализатор Java или C #. По этой причине вы не можете использовать RAII на JVM или CLR (блоки using
C # вы получите около 95% пути, но это немного отличается …).
Однако Google, похоже, указывает, что PHP поддерживает шаблон RAII , хотя я не могу найти подтверждение этого в документах PHP. Поддерживает ли язык этот язык и ставит логику очистки в __destruct
достаточным для выполнения задач RAII?
Это почти тот же вопрос, что и Деструктор в PHP предсказуем? и ответ тот же. PHP использует refcounting, и он обещает, что деструктор будет вызываться немедленно, как только refcount будет равен нулю (обычно, когда объект выходит за рамки). Поэтому, если вы создаете объект и стараетесь не выходить из него, RAII жизнеспособна.
PHP использует подсчет ссылок, поэтому, когда вы закончите с переменной, она будет немедленно очищена. (Если вы не создаете циклы.) Это быстро освобождает ресурсы, поэтому вам вообще не нужно беспокоиться о явном управлении ресурсами, кроме того, чтобы не создавать циклы памяти.
Если вы хотите реализовать какую-либо конкретную стратегию, вы можете сделать это, убедившись, что ресурс используется только одной переменной. Всякий раз, когда эта переменная указана в стороне от ресурса, ресурс должен быть немедленно освобожден.
Следующий класс ReturnHandler
обеспечивает автоматический вызов обработчика, когда ReturnHandler
выходит из области видимости. Вы можете иметь несколько return
в своей функции ( myfunc
) без необходимости думать о выпуске ресурса перед каждым из них.
/** * 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(); } }
Вот тест на это:
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); } }