【问题标题】:Catching a Thrown Exception from a Static Method从静态方法中捕获抛出的异常
【发布时间】:2013-07-08 22:09:31
【问题描述】:

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

代码流:一个请求到达 index.php 页面,该页面引入了一个引导文件。该引导文件定义常量,引入其他文件,注册函数等,以“启动”系统。引导程序做了两个主要的事情:定义/注册我的自动加载函数,然后通过需要一个包含异常处理代码的 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();
    }
}
  1. 如果我删除 catch/try,我会收到致命的“未捕获 PDOException”错误。
  2. 如果我尝试在带有 PDOExceptoin 消息的 catch 块中重新抛出一个新异常,那么 PHP 在页面底部会吐出一条致命错误消息。它还会输出异常消息和完整的异常跟踪。
  3. 如果我在 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 并没有真正按顺序调用它们,只是最后一个注册的函数?

编辑: 我尝试了以下方法来确认一些事情。

  1. 正在加载error.php 文件。如果我在文件中定义一个常量并稍后在 index.php 文件中打印出来,它就会打印出来。
  2. 在我的引导程序包含在索引页面中后,我可以在 index.php 中抛出异常并且异常按预期执行
  3. 我可以从给出异常的静态 DB 函数中打印出错误消息,因此 try/catch 处理在静态函数内部工作

【问题讨论】:

  • 你确定你在抛出这个异常之前注册了你的默认处理程序......这似乎应该可以工作
  • 是的。打开 PHP 标记后的第一行是引导程序的 include,其中包括 error.php(如上所示)。在 include 之后,系统开始工作——启动会话、路由等。我还在 error.php 文件中定义了一个值,并在 index.php 文件中回显它以测试 require 是否正常工作
  • 我根本无法解决您的问题。想添加一个 TLDR 以回答您想要回答的问题吗?谢谢。
  • 抱歉,我只是想提供所有细节,因为很多时候人们最终要求更多。此外,仅仅因为你没有得到它并不意味着其他人没有。问题很简单,当我的网站索引启动时,它会抓取我的引导程序,它会注册我的自动加载程序和异常处理程序。控制权返回索引后,它立即调用我的 Session 类。如果会话类抛出错误,即使其他异常被其他地方捕获,它也不会捕获它。

标签: php exception-handling pdo


【解决方案1】:

不确定这是否有帮助:如果您正在使用命名空间(您应该这样做),那么请确保您访问的是正确的 Exception 类。

要么放在你的标题中

use Exception;

或在你的 catch 语句中添加反斜杠

} catch (\Exception $e) {

否则 PHP 将在您的命名空间内搜索异常类。

【讨论】:

    【解决方案2】:

    在您的 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;
    

    【讨论】:

    • 谢谢,但只是去掉空格并没有做任何事情。不过很好,他们不应该在那里
    【解决方案3】:
    } catch (Exception $e) { 
        return $e->getMessage();
    }
    

    -- 这就是为什么你的处理程序没有捕获任何东西的原因。
    因为你已经手动抓到了。

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

    在抛出异常时检查您的处理程序是否准备就绪。然后再检查一遍。

    【讨论】:

    • 我明白这一点,但正如我上面提到的,我必须有某种 try/catch 块来捕获错误,以避免致命的未捕获异常错误,因为我的异常处理程序没有到达无论出于何种原因进入我的课程。我会检查时间建议
    猜你喜欢
    • 1970-01-01
    • 2010-10-08
    • 2020-01-28
    • 1970-01-01
    • 2017-01-04
    • 2011-06-27
    • 2011-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多