更新:解決済み
私はついに自分の問題を理解しました(私は思います)。問題は、クロージャーをシリアル化できないこと、つまり、クロージャーをセッションに保存できないことだと確信しています。次の問題は、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行目の不明でスタックフレームなしで例外がスローされました
これは本当に意味がありません。デフォルトのセッションハンドラーに戻ったようですが、tmpファイルが開かれなかったため(私の関数がセッションの開きを引き継いだため)、もちろん失敗します。セッションにクロージャを保存すると、なぜそのような復帰が発生するのか、またはこれが一般的に壊れているのか、私にはわかりません。どんな助けでもいただければ幸いです。