我正在编写一个将消息写入文件的日志工具,我不确定处理文件指针的最佳方法。我在这两种方法之间徘徊:
// 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");
}
我想这个类将在每个页面上加载和构建,但不一定会使用,尽管很可能会这样。
这两种方法都存在性能,安全性或其他缺陷吗?您会推荐哪种方法?
答案 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
方法添加一些代码。