是一个PHP类析构函数,总是在Apache HTTP请求线程上下文中调用


Is a PHP class destructor always called in the Apache HTTP request thread context?

我有一个PHP应用程序(PHP 5.3),其中日志记录是在类析构函数中完成的。

/**
 * @return void
 */
public function __destruct() {
    $string = ...
    $file = new SplFileObject('filename', 'a');
    $file->fwrite($string."'n");
}

只有一个服务器在做日志记录。基本上,执行日志记录的代码保存当前时间戳(请求结束)以及其他信息,如持续时间…

奇怪的是,当我查看日志时,时间戳并不总是按时间顺序出现。我差了差不多2分钟。例如(我的日志):

2014-05-10 14:30:00 log1
2014-05-10 14:28:00 log2 (ended 2 minutes before previous log)
2014-05-10 14:30:01 log3
2014-05-10 14:30:02 log4

当我查看Apache日志时,我的时间戳与Apache的时间戳匹配(除了顺序)。

2014-05-10 14:28:00 log2
...
2014-05-10 14:30:00 log1
2014-05-10 14:30:01 log3
2014-05-10 14:30:02 log4

我能想到的唯一解释是析构函数不是由HTTP线程调用的,而是稍后由另一个线程调用的。谁能证实这一点或提供另一个(文档化的)解释?

如果析构函数写入文件,可以通过获取fwrite()的返回值来轻松测试,如下所示

public function __destruct() {
    $string = ...
    $file = new SplFileObject('filename', 'a');
    $number_of_bytes = $file->fwrite($string."'n");
    echo "Wrote $number_of_bytes bytes to log file";
}

旁注:析构函数不应用于新的业务逻辑,而应用于清理已分配的资源。我建议你使用事件/钩子来记录日志。

另外需要考虑的是:PHP手册建议不要对session_write_close使用析构函数。相反,他们倾向于使用register_shutdown_function()

register_shutdown_function('log');
function log() {
    $string = ...
    $file = new SplFileObject('filename', 'a');
    $number_of_bytes = $file->fwrite($string."'n");
    echo "Wrote $number_of_bytes bytes to log file";
}