cgtag / php-disposable
一个为PHP添加可丢弃模式的微型库
Requires
- php: >=7.1.0
Requires (Dev)
- phpunit/phpunit: >=5.7,<6
This package is not auto-updated.
Last update: 2024-09-28 20:45:56 UTC
README
一个为PHP添加可丢弃模式的微型库
需求
PHP 7.1或以上(目前至少PHP 7.1.0)
安装
您可以使用以下命令通过Composer轻松安装此库:Composer
$ composer require cgtag/php-disposable
文档
使用此库的基本说明是实现IDisposable
接口并声明一个实现所有资源清理逻辑的dispose()
方法。
以下示例显示了基本模式的一个简单实现。
use cgTag\Disposable\IDisposable;
class ResourceHolder implements IDisposable {
private $file;
public function __constructor(string $filename) {
$this->file = fopen($filename, "r");
}
public function read() {
return stream_get_contents($this->file);
}
public function dispose() {
if($this->file) {
fclose($this->file);
}
$this->file = null;
}
}
现在您可以使用全局的using
函数在完成对象使用后销毁该对象。
以下是using
函数的一个示例
$content = using(new ResourceHolder(), function($resource) {
return $resource->read();
});
这看起来很简单,但一旦您开始遵循可丢弃模式,内存泄漏将成为过去式。
dispose()
确保将dispose()
的调用传播到继承类中。您可以通过重写dispose()
方法并确保调用parent::dispose()
来实现这一点。
注意:
dispose()
只会被调用一次。它将在调用__destruct()
之前作为类上执行的最后一个方法。由于在调用时将调用dispose()
,因此您不必担心之后使用属性。您不必担心属性在之后被使用,因为dispose()
会被调用。
IDisposable
接口
这是库中使用的首要接口。在PHP中,垃圾收集器会在对象不再使用时自动释放分配给托管对象的内存。然而,无法预测垃圾收集何时发生。此外,垃圾收集器对未管理资源(如文件句柄、图像和流)没有任何了解。
如果使用此接口,请使用dispose()
方法显式释放未管理资源,并配合垃圾收集器。当对象不再需要时,对象的使用者可以调用此方法。
全局using()函数
提供一个便利函数,确保正确使用IDisposable
对象。以下示例显示了如何使用全局using()
函数。
using(new ConfigReader("config.ini"), function(ConfigReader $reader) {
$debug = $reader->get('debug');
});
using函数确保即使在调用对象的方法时发生异常,也会调用dispose()
。您可以通过在try块中放置对象并在finally块中调用dispose()
来实现相同的结果;实际上,这正是using
函数的编写方式。前面的代码示例可以写成以下示例
$reader = new ConfigReader("config.ini");
try {
$debug = $reader->get('debug');
} finally {
$reader->dispose();
}
您可以实例化资源对象,然后将变量传递给using
函数,但这不是最佳实践。在这种情况下,即使它可能不再有权访问其未管理资源,对象也会在控制离开using
块后保持作用域。换句话说,它将不再完全初始化。如果您在using
回调之外尝试使用对象,则可能会抛出异常。因此,通常最好将对象作为传递给using
的参数实例化,并将作用域限制在using
回调中。
$reader = new ConfigReader("config.ini");
using($reader, function(ConfigReader $reader) {
// use reader
});
// reader is still in scope, but calling it throws an exception
$debug = $reader->get('debug');
注意:
using
不应与use
混淆
DisposableTrait
DisposeTrait
允许对象自动释放公共属性。当一个对象实现了 IDisposable
接口并在对象被释放时使用 DisposeTrait
,则所有引用 IDisposable
对象的公共属性也将被释放并取消设置。该特性还会深度遍历所有公共数组,释放数组中的任何对象。
以下是一个使用上面示例中的 ConfigReader
的对象示例
use cgTag\Disposable\IDisposable;
use cgTag\Disposable\Traits\DisposeTrait;
class Service implements IDispose {
use DisposeTrait;
public $reader;
public function __constructor() {
$this->reader = new ConfigReader("config.ini");
}
}
私有属性和内存泄漏
DisposeTrait
无法释放私有属性,但当私有属性引用实现 IDisposable
接口的对象时,会抛出异常。特性这样做是因为它发现了一个可能的内存泄漏。由于对象正在使用特性且不支持私有属性,这意味着该属性可能没有被释放。
为了解决这个冲突,请将属性设置为公共的或在对象上实现 dispose()
方法。
许可证
php-disposable 在 MIT 许可证下授权 - 有关详细信息,请参阅 LICENSE 文件