在PHP中打开文件句柄的开销成本?

时间:2009-10-23 01:45:48

标签: php performance file logging

我正在编写一个将消息写入文件的日志工具,我不确定处理文件指针的最佳方法。我在这两种方法之间徘徊:

// Open, Write, Close; Open, Write, Close...
function write($message) {
    $fh = fopen('file.log', 'a');
    fwrite($fh, $message . "\n");
    fclose($fh);
}

// OR -----

// Open, Write, Write, Write..., Close
function __construct() {
    $this->fh = fopen('file.log', 'a');
}
function __destruct() {
    fclose($this->fh);
}
function write($message) {
    fwrite($fh, $message . "\n");
}

我想这个类将在每个页面上加载和构建,但不一定会使用,尽管很可能会这样。

这两种方法都存在性能,安全性或其他缺陷吗?您会推荐哪种方法?

4 个答案:

答案 0 :(得分:2)

我不能给你一个号码,但打开一个文件只是为了关闭并重复打开它会花费你一些钱。而我正在谈论操作系统级别,而不仅仅是PHP。调用内核open()(或CreateFile()如果你说Windows),将路径字符串与文件系统中的实体匹配,从磁盘读取目录结构,然后另一个系统调用来关闭句柄...特别是如果你有大量的这个我会避免这么做太多。或者进行一些测量,看看是否正常。

如果您担心因永远不会使用的东西会产生成本,您是否考虑过这两种方法的混合?也就是说,如果文件尚未打开,则执行打开,否则重用旧句柄...

答案 1 :(得分:1)

取决于您正在记录的内容。

真的第二个版本是最好的。可以这样想:

您想记录在请求的周期中发生的错误。假设您在请求期间遇到3个错误。如果您使用第一种方法,则打开和关闭文件3次会导致更多开销。如果您使用的是记录器类的相同实例,则只需打开一次文件并在请求期间向其写入3行。

希望这能为您解决问题。

您可以选择将文件指针传递给第一个方法,并且只让该方法执行写入。

答案 2 :(得分:1)

以下是替代版本:

function log($message) {
  global $_log;
  if (!defined(LOG_OPEN)) {
    define(LOG_OPEN, true);
    $_log = fopen('filename.log', 'w');
    register_shutdown_function('close_log');
  }
  fwrite($_log, $message . "\n");
}

function close_log() {
  global $_log;
  fclose($_log);
}

至少那时你只是在写邮件时打开日志。

它会花费你一些东西。在网络延迟成本的宏观方案中,除非你开始打开大量文件,否则我怀疑它将是重要的。我怀疑这个日志的效果是否可以衡量。

答案 3 :(得分:1)

第二种方法显然更好,IMO。打开和关闭文件句柄确实有成本,虽然它相对较小,但如果你在应用程序中做了很多事情,它确实会增加很多(尽管如果这是非常罕见的,它将没有什么区别我不认为)。如果您需要添加一些额外的设置或清理功能,第二种方法将是最干净的,因为您只需向__construct / __destruct方法添加一些代码。