我可以通过取消设置手柄来关闭文件吗?

时间:2012-06-07 09:12:26

标签: php resources

如果我可以通过取消设置带有句柄的变量来省略fclose命令,我会感到有点困惑吗?

$handle = fopen($file);
...
fclose($handle);

... // script goes on for a long

与:

相比
$handle = fopen($file);
...
unset($handle);

... // script goes on for a long

洞察任何人?

4 个答案:

答案 0 :(得分:3)

  

由于PHP 4的Zend引擎引入了引用计数系统,自动检测到一个没有更多引用的资源,它被垃圾收集器释放。

考虑这个的含义。可以安全地假设垃圾收集后变量的所有痕迹都消失了。换句话说,在PHP执行结束时,如果PHP仍未跟踪引用,它将如何关闭它?因此,当垃圾收集器吃它时它会关闭它似乎是合乎逻辑的。

这是一个错误的逻辑论证,因为它假定垃圾收集在未设置后立即或不久发生,并且PHP不会保留对用户域中不再存在的变量的隐藏引用。


如果PHP在超出范围时没有关闭文件句柄,那么更具吸引力的案例可能是潜在的行为缺陷。考虑一种打开大量文件的守护进程。现在考虑是否永远不会调用fclose。相反,允许变量超出范围或在其上显式调用unset。

如果这些文件句柄没有关闭,这个长时间运行的守护程序就会用完文件句柄。


潜在行为特定测试脚本:

<?php

$db = mysql_connect(...);

if ($db) {
    echo "Connected\n";
    sleep(5); //netstat during this just for paranoia
    unset($db);
    echo "Unset\n";
    sleep(5); //netstat during this and the connection is closed
}

在Windows 7和Debian 6上,未设置后连接已关闭。

显然,这只能证明在我的特定机器上使用我的特定PHP版本会有效。对文件句柄等没有任何意义:)。


我现在正在搜索PHP源代码以获取硬性证据

答案 1 :(得分:2)

PHP文档暗示所有没有剩余引用的资源都被“释放”,我假设对于文件句柄,这将包括关闭文件。

简单的测试用例:

$f = fopen("test.php", "r");
if (!flock($f, LOCK_EX)) {
  print("still locked\n");
  exit;
}
unset($f);
sleep(5);
print("goodbye\n");

(我已将其保存为test.php,因此它会自行锁定;可能需要将fopen()中的文件名更改为某些现有文件,否则

在5秒内运行脚本两次;如果你“仍然被锁定”,那么显然未设置手柄并没有释放锁定。在我的测试中,我做了得到“仍然被锁定”,所以显然未设置句柄至少释放锁,尽管在垃圾收集时释放锁似乎很愚蠢,但不要关闭文件。

答案 2 :(得分:1)

unset($handle)将销毁$handle变量,但不会关闭$handle指向的文件。您仍然需要致电fclose()来关闭该文件。

答案 3 :(得分:0)

一些研究:

fclose使$handle成为resource(5) of type (Unknown)

unset使其成为NULL

并且在fclose之后,php消耗了88个字节的内存。

所以:他们是不同的=)