Reputation: 1695
I am attempting to implement exception handling into my project and have hit a bit of a head scratcher.
Code flow: A request hits the index.php page, which brings in a bootstrap file. That bootstrap file defines constants, brings in other files, registers functions, etc, to "start" the system. The bootstrap does two main big things: defines/registers my autoload function, then does the same for exception handling by requiring an error.php file with the exception handling code in it. After the bootstrap file loads, routing happens and away the system goes.
My issue comes from the following. I have a folder of class files in the system. Just classes with static methods for various uses - database, sessions, user, etc. All these classes throw various exceptions (standard and SPL) which my registered exception handler catches. However, the exception handler isn't catching thrown exceptions for the Session class.
The session class is a class (regular, not abstract/static) with static methods that "extend"/"replace" the default PHP session functions with custom ones in order to store session data in a database. In the start() function I register the appropiate functions with the php session "handles" via the session_set_save_handler function. I also call register_shutdown_function as suggested by php.net to ensure session data is saved if the app must abruptly stop.
Here is some code of my session class that was throwing a PDOExceptoin because my SQL was wrong - DB is just a wrapper for 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();
}
}
Here is my exception handling error.php file
// 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");
I do realize that my SQL statement is wrong and that is causing the PDOException, but I'm leaving it at the moment to figure out my exception bug.
I believe it has something to do with the fact that I'm calling register_shutdown_function twice in two different spots even though PHP says that it legal and the functions will be called in the order they are registered, so maybe my order is backwards or maybe PHP doesn't really call them in order, just the last function registered?
Edit: I have tried the following to confirm a few things.
Upvotes: 1
Views: 5957
Reputation: 151
Not sure if this helps: If you're using namespaces (which you should), then make sure you are accessing the correct Exception class.
Either put in your header
use Exception;
or add the backslash to your catch statement
} catch (\Exception $e) {
Otherwise PHP will be searching for an exception class inside your namespace.
Upvotes: 4
Reputation: 157839
} catch (Exception $e) {
return $e->getMessage();
}
-- this is why your handler doesn't catch anything.
Because you already caught it manually.
If I delete the catch/try, I get a fatal "uncaught PDOException" error.
Check if your handler is ready by the time exception is thrown. Then check it again.
Upvotes: 0
Reputation: 24645
In your set_exception_handler you have $e ->getLine()
... remove the space... I think what might be happening is this is causing an exception (ErrorException) to be raised from within your exception handler which is what you are seeing, because there is nothing to catch that exception.
you are probably better off doing something like this:
$error = "<div style='text-align: center;'>";
$error .= "<h2 style='color: rgb(190, 50, 50);'>".get_class($e)." Occured:</h2>";
$error .= "<table style='width: 800px; display: inline-block;'>";
$error .= "<tr style='background-color:rgb(240,240,240);'><th>Message</th>";
$error .= "<td>".$e->getMessage()."</td></tr>";
$error .= "<tr style='background-color:rgb(230,230,230);'><th>File</th>";
$error .= "<td>".$e->getFile()."</td></tr>";
$error .= "<tr style='background-color:rgb(240,240,240);'><th>Line</th>";
$error .= "<td>".$e->getLine()."</td></tr>";
$error .= "</table></div>";
echo $error;
Upvotes: 0