プロジェクトに例外処理を実装しようとしていますが、頭を悩ませています。
コード フロー: リクエストが index.php ページにヒットし、ブートストラップ ファイルが取り込まれます。そのブートストラップ ファイルは、定数を定義し、他のファイルを取り込み、関数を登録するなどして、システムを「開始」します。ブートストラップは主に 2 つの大きなことを行います。autoload 関数を定義/登録し、例外処理コードを含む error.php ファイルを要求することで、例外処理についても同じことを行います。ブートストラップ ファイルが読み込まれると、ルーティングが行われ、システムは終了します。
私の問題は次のとおりです。システムにクラスファイルのフォルダーがあります。データベース、セッション、ユーザーなど、さまざまな用途の静的メソッドを持つクラスだけです。これらのクラスはすべて、登録された例外ハンドラーがキャッチするさまざまな例外 (標準および SPL) をスローします。ただし、例外ハンドラーは、Session クラスに対してスローされた例外をキャッチしていません。
セッションクラスは、セッションデータをデータベースに保存するために、デフォルトの PHP セッション関数をカスタム関数で「拡張」/「置換」する静的メソッドを持つクラス (通常、抽象/静的ではない) です。start() 関数では、session_set_save_handler 関数を介して適切な関数を php セッション「ハンドル」に登録します。また、php.net で提案されているように register_shutdown_function を呼び出して、アプリが突然停止する必要がある場合にセッション データが確実に保存されるようにします。
SQL が間違っていたために PDOExceptoin をスローしていたセッション クラスのコードを次に示します。DB は PDO の単なるラッパーです。
public static function write($id, $data) {
try {
$expires = time() + self::$lifetime;
$sql = "INSERT INTO sessions (session_id, session_data, expires) VALUES (?,?,?) ON DUPLICATE KEY UPDATE SET session_data = ? WHERE session_id = ? ";
if (DB::query($sql, array($id, $data, $expires, $data, $id))->rowCount() > 0) {
return true;
} else {
return false;
}
} catch (Exception $e) {
return $e->getMessage();
}
}
- catch/try を削除すると、致命的な "uncaught PDOException" エラーが発生します。
- PDOExceptoin メッセージを使用して catch ブロックで新しい例外を再スローしようとすると、PHP はページの下部に致命的なエラー メッセージを吐き出します。また、例外メッセージと完全な例外トレースも吐き出します。
- catch ブロックで例外メッセージをエコーすると、正常に出力され、致命的なキャッチされていない例外エラーは表示されません。
これが私の例外処理error.phpファイルです
// Error handler function
function log_error($num, $str, $file, $line, $context = null) {
log_exception(new ErrorException($str, 0, $num, $file, $line));
}
// Exception handler function
function log_exception($e) {
if (DEBUG) {
$type = get_class($e);
$trace = $e->getTrace();
$error = /* Code that creates an HTML table for pretty exception printing */;
echo "";
echo $error;
echo "";
} else {
$message = "Type: " . get_class($e) . "; Message: {$e->getMessage()}; File: {$e->getFile()}; Line: {$e ->getLine()};";
file_put_contents(SYSPATH . "/private/log/exceptions.log", $message . PHP_EOL, FILE_APPEND);
header("Location: 500.html");
}
}
// Checks for a fatal error, work around for set_error_handler not working on fatal errors.
function check_for_fatal() {
$error = error_get_last();
if ($error["type"] == E_ERROR)
log_error($error["type"], $error["message"], $error["file"],$error["line"]);
}
set_error_handler("log_error");
set_exception_handler("log_exception");
register_shutdown_function("check_for_fatal");
SQL ステートメントが間違っていて、それが PDOException の原因であることは認識していますが、例外のバグを把握するために、現時点ではそのままにしておきます。
PHPは合法であり、関数は登録された順序で呼び出されると言っているにもかかわらず、2つの異なる場所でregister_shutdown_functionを2回呼び出しているという事実と関係があると思います。実際にそれらを順番に呼び出すのではなく、登録された最後の関数だけですか?
編集:いくつかのことを確認するために、次のことを試しました。
- error.php ファイルがロードされています。ファイルで定数を定義し、後で index.php ファイルに出力すると、出力されます。
- インデックス ページにブートストラップをインクルードした後、index.php で例外をスローできます。例外は期待どおりに動作します。
- 例外を発生させている静的 DB 関数からエラー メッセージを出力できるので、try/catch 処理は静的関数内で機能しています。