从静态方法捕获抛出的异常


Catching a Thrown Exception from a Static Method

我正试图在我的项目中实现异常处理,但遇到了一些麻烦。

代码流:一个请求到达index.php页面,该页面会带来一个引导文件。该引导文件定义常量,引入其他文件,注册函数等,以"启动"系统。引导程序主要做两件大事:定义/注册我的自动加载函数,然后通过要求一个包含异常处理代码的error.php文件来进行异常处理。引导程序文件加载后,路由发生,系统离开。

我的问题来自以下方面。我在系统中有一个类文件文件夹。只是具有用于各种用途的静态方法的类——数据库、会话、用户等。所有这些类都会抛出各种异常(标准和SPL),我注册的异常处理程序会捕捉到这些异常。但是,异常处理程序并没有捕获Session类的抛出异常。

会话类是一个具有静态方法的类(常规的,而不是抽象的/静态的),这些方法用自定义方法"扩展"/"替换"默认的PHP会话函数,以便将会话数据存储在数据库中。在start()函数中,我通过session_set_save_handler函数向php会话"handles"注册appropiate函数。我还按照php.net的建议调用register_shutdown_function,以确保在应用程序必须突然停止时保存会话数据。

以下是我的会话类的一些代码,因为我的SQL错误而引发了PDOExceptin——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();
    }
}
  1. 如果我删除catch/try,我会得到一个致命的"未捕获的PDOException"错误
  2. 如果我试图用PDOExceptin消息在catch块中重新抛出一个新的Exception,那么PHP会在页面底部弹出一条致命的错误消息。它还吐出异常消息和完整的异常跟踪
  3. 如果我在catch块中回显异常消息,它将打印出良好且没有致命的未捕获异常错误

这是我的异常处理错误.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");

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.

  1. The error.php file is being loaded. If I define a constant in the file and print it out later on in the index.php file, it prints out.
  2. After my bootstrap include in the index page, I can throw an exception in the index.php and the exception performs as expected
  3. I can print out the error message from the static DB function that is giving the exception, so the try/catch handling is working inside the static function

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;

或者在catch语句中添加反斜杠

} catch ('Exception $e) {

否则,PHP将在您的命名空间中搜索一个异常类。

在您的set_exception_handler中,您有$e ->getLine()。。。删除空间。。。我认为可能发生的情况是,这会导致从您的异常处理程序中引发异常(ErrorException),这就是您所看到的,因为没有任何东西可以捕获该异常。

你最好做这样的事情:

$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;
} catch (Exception $e) { 
    return $e->getMessage();
}

--这就是为什么你的处理程序什么都没抓到的原因
因为你已经手动捕捉到了。

如果我删除catch/try,我会得到一个致命的"未捕获的PDOException"错误。

在抛出异常时,请检查处理程序是否已准备就绪。然后再次检查。