更新:已解决
我终于弄清楚了我的问题(我认为)。我很确定问题是闭包不能序列化,这意味着它们不能存储在会话中。下一个问题是 PHP 没有返回一个非常有用的错误,并且以一种意想不到的方式中断,而不是仅仅告诉我我无法序列化闭包。
我将会话数据存储在 mysql 数据库中。我已经准备好我的应用程序的这一部分,并且运行良好了很长一段时间。今天我试图在会话中存储一个闭包(即匿名函数),这破坏了我原本表现良好的会话。
我的会话管理由一个对象处理,当 PHP 尝试销毁该对象时,该对象会自动调用 session_write_close()。我这样做是因为否则,当 PHP 尝试关闭会话时,我的数据库连接(一个 mysqli 对象)已经被破坏了。
我像这样接管会话处理:
// set the session save handler
session_set_save_handler(
array( $this, '_open' ),
array( $this, '_close' ),
array( $this, '_read' ),
array( $this, '_write' ),
array( $this, '_destroy' ),
array( $this, '_clean' )
);
这是相当标准的。处理会话关闭的部分是这样的:
public function __destruct()
{
// this variable will only be destroyed when the script is closing
// at this point it is safe to close the session
// if we wait for php to close the session then we will
// have lost the database connection, so we do it now
session_write_close();
}
// write session data
public function _write( $sid, $data )
{
// run query to write to database
$now = NOW;
$stmt = $this->mysqli->prepare( "REPLACE INTO $this->table (sid,time,data) VALUES (?,?,?)" );
$stmt->bind_param( 'sis', $sid, $now, $data );
// execute
$success = $stmt->execute();
// close
$stmt->close();
// and return
return $success;
}
// close session store
public function _close()
{
// close the database connection
$this->mysqli->close();
return true;
}
几个打印函数表明,这通常像你想象的那样工作:调用 __destruct() 函数,该函数调用 session_write_close(),紧接着调用 _write() 和 _close()。但是,当我存储会话的关闭时:
$test = function($name)
{
print "Hello $name";
};
$_SESSION['test'] = $test;
一切都破裂了。__destruct() 像以前一样被调用,但执行永远不会到达 _write() 或 _close() 函数。相反,我收到这些消息:
警告:session_write_close() [function.session-write-close]:无法写入会话数据(用户)。请在第 48 行的 /var/www/vhosts/ambida.com/httpdocs/includes/core/session_handler.php 中验证 session.save_path 的当前设置是否正确(/var/lib/php/session)
致命错误:在第 0 行的 Unknown 中抛出没有堆栈帧的异常
这真的没有任何意义。看起来它已恢复为默认会话处理程序,这当然会失败,因为 tmp 文件从未打开(因为我的函数接管了打开会话)。我不明白为什么在会话中存储一个闭包会导致这种恢复发生,或者为什么这通常会中断。任何帮助,将不胜感激。