PHP支持RAII模式吗?怎么样?

时间:2011-02-08 21:29:00

标签: php raii

PHP上的大多数资源从不接触内存管理,因为语言本身非常适合为您执行此操作。但是,在PHP中,您通常最终会处理不是内存的外部资源 - 数据库句柄,会话,数据库事务等。这些外部资源可以使用某种形式的RAII对象进行最干净的管理。

我最初认为PHP使用类似于JVM或CLR的垃圾收集方案,其中析构函数的概念不存在。 (记住:Everyone thinks about garbage collection the wrong way - 终结器不是析构函数!)有特殊的__destruct方法,但我认为这是一个类似于Java或C#终结器的“终结器”。出于这个原因,你不能在JVM或CLR上使用RAII(C#的using块可以让你获得大约95%的路径,但这有点不同......)。

然而,Google seems to indicate that PHP supports the RAII pattern,虽然我在PHP文档中找不到对此的验证。语言是否支持这一点,并且正在使__destruct中的清理逻辑足以完成RAII任务?

4 个答案:

答案 0 :(得分:10)

这与Is destructor in PHP predictable?几乎是同一个问题,答案是一样的。 PHP使用refcounting,它承诺一旦refcount变为零(通常当对象超出范围时)就会立即调用析构函数。因此,如果您创建一个对象并注意不要将其泄漏到范围之外,那么RAII就是可行的。

答案 1 :(得分:4)

PHP使用引用计数,因此当您完成变量后,它会立即被清除。 (除非你创建周期。)这会立即释放资源,因此除了小心不创建内存周期之外,通常不需要担心显式资源管理。

如果您确实想要实施任何特定策略,可以通过确保资源仅由一个变量使用来实现。每当该变量指向远离资源时,应立即释放资源。

答案 2 :(得分:2)

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

答案 3 :(得分:0)

有点题外话:您可以使用lambda做类似using的模式。像这样:

function WithFile($Name, $Func)
{
    $File = fopen($Name, 'r');
    $r = $Func($File);
    fclose($File);
    return $r;
}

然后像这样使用它

$FileHeader = WithFile('myfile', function($File) {return fread($File, 16);});

完全确定的。也就是说,lambdas是否有更简短的语法...