PHP 支持 RAII 模式吗?如何?

发布于 2024-10-16 15:26:56 字数 683 浏览 2 评论 0原文

PHP 上的大多数资源从不涉及内存管理,因为该语言本身非常擅长为您做到这一点。然而,在 PHP 中,您经常最终会处理非内存的外部资源——数据库句柄、会话、数据库事务等。可以使用某种形式的 RAII 对象来最干净地管理这些外部资源。

我最初认为 PHP 使用了类似于 JVM 或 CLR 的垃圾收集方案,其中不存在析构函数的概念。 (请记住:每个人都以错误的方式思考垃圾收集——终结器不是析构函数!)有特殊的 __destruct 方法,但我认为这是一个类似于 Java 或 C# 终结器的“终结器”。因此,您无法在 JVM 或 CLR 上使用 RAII(C# 的 using 块可以完成大约 95% 的工作,但这有点不同......)。

不过,Google似乎表明 PHP 支持 RAII 模式,尽管我在 PHP 文档中找不到对此的验证。该语言是否支持这一点并将清理逻辑放入 __destruct 中足以完成 RAII 任务?

Most resources on PHP never touch memory management because the language itself is pretty good at doing this for you. However, in PHP you often end up dealing with external resources which aren't memory -- database handles, sessions, database transactions, etc. These external resources could be managed most cleanly using some form of RAII object.

I initially thought that PHP used a garbage collection scheme similar to the JVM or the CLR, where the concept of a destructor does not exist. (Remember: Everyone thinks about garbage collection the wrong way -- finalizers are not destructors!) There's the special __destruct method, but I thought that was a "finalizer" similar to a Java or C# finalizer. For this reason, you cannot use RAII on the JVM or the CLR (C#'s using blocks get you about 95% of the way there, but that's a bit different...).

However, Google seems to indicate that PHP supports the RAII pattern, though I cannot find verification of this in the PHP docs. Does the language support this and is putting the cleanup logic in __destruct sufficient for accomplishing RAII tasks?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

Oo萌小芽oO 2024-10-23 15:26:56

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

This is nearly the same question as Is destructor in PHP predictable? and the answer is the same. PHP uses refcounting, and it promises that the destructor will be called immediately as soon as the refcount goes to zero (generally when the object goes out of scope). So if you create an object and take care not to leak it out of scope, RAII is viable.

一梦浮鱼 2024-10-23 15:26:56

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

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

PHP uses reference counting, so when you're done with a variable it gets cleaned up immediately. (Unless you create cycles.) That frees up resources promptly so you generally don't need to worry about explicit resource management beyond being careful to not create memory cycles.

If you did want to implement any particular strategy, you can do it by making sure that the resource is only used by one variable. Whenever that variable is pointed away from the resource, the resource should be immediately freed up.

纵性 2024-10-23 15:26:56

ReturnHandler 的实例超出范围时,以下类 ReturnHandler 提供处理程序的自动调用。您的函数 (myfunc) 中可以有多个 return,而无需考虑在每个 return 之前释放资源。

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

The following class ReturnHandler provides automatic invocation of a handler when ReturnHandler's instance goes out of scope. You can have several returns in your function (myfunc) without the need to think of releasing the resource before each of them.

/**
 * 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();
  }
}

Here's a test for it:

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);
  }
}
套路撩心 2024-10-23 15:26:56

稍微偏离主题:您可以使用 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);});

完全确定性。也就是说,是否有更简洁的 lambda 语法...

Slightly offtopic: you can do a using-like pattern with lambdas. Like this:

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

And then use it like this

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

Perfectly deterministic. That said, were there a terser syntax for lambdas...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文