PHP 未在类中抛出指定的错误消息

PHP not throwing specified error message in Class

提问人:Hmerman6006 提问时间:5/16/2020 最后编辑:DharmanHmerman6006 更新时间:5/16/2020 访问量:298

问:

我有三个类,每个类在连接到我的数据库时处理不同的功能。
具有处理连接的名称的类 1;带名称的类 2 通过用户 UI 的键提供错误和成功消息,带名称的类 3 使用 MySqli 连接从数据库中检索数据并将其传递给 UI。

这与我通常进行数据库连接、收集和显示的方式不同。通常,我只是在三个文件中创建了很多函数,并在需要时调用它们。但是我的网站越来越大,越来越复杂,所以我正在重新组织一切。
我目前的问题是,当我在我的第三个类中创建数据库连接时,它没有抛出我编程的错误。
ConnectDB()MySqli()MessageOut()$_SESSION['message']WebApp()

class ConnectDB {
    //Connecting to database
    public function connect() {
        //connecting to mysql
        @$conn = new mysqli(DB_HOST, DB_USERRW, DB_PASSWRW, DB_DBASE);
        // check validity of database connection
        if (mysqli_connect_errno()) {
            return false;
            exit();
        }
        // select the database to use
        return $conn;
    }
}

ini_set('display_errors', 1); 
    ini_set('log_errors',1); 
    error_reporting(E_ALL); 
    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
class WebApp {
    protected $db;
    function __construct(){
        $this->connector = new ConnectDB();
        $this->messager = new MessageOut();
        try {
            $this->db = $this->connector->connect();
            if(!$this->db) {
                throw new Exception(' Database connection is currently unavailable.');
            }
        } catch (Exception $e) {
            mysqli_report(MYSQLI_REPORT_OFF);
            $errors = array();
            $message = $e->getMessage();
            //populate array with message and divert output to error class functions
            array_push($errors, $message);
            $this->messager->erroutput($errors);
        }
    }
    public function selectIdata() {
        //select data
        try {
            $query = "SELECT *
                        FROM thetable";
            $stmt = $this->db->prepare($query);
            $stmt->execute();
            $stmt->store_result();

            $stmt->bind_result($idata);
            $result = [];
            if ($stmt->num_rows > 0) {
                while ($stmt->fetch()) {
                    $result[] = $idata;
                }
                return $result;
            } else {
                return false;
            }
        } catch (Exception $e) {
            mysqli_report(MYSQLI_REPORT_OFF);
            $errors = array();
            $message = $e->getMessage();
            //populate array with message and divert output to error class functions
            array_push($errors, $message);
            $this->messager->erroutput($errors);
        }
    }
}

我将我的 localhost 定义的密码更改为错误的密码并加载了文件,但即使错误被禁止,错误也在我的第一类中的第 10 行给出。这个想法是在使用前检查连接。
如何在我的第三节课中抛出错误,提示“数据库连接当前不可用”消息?

编辑
所以我重新评估了我所做的事情,并在我的第 3 节课中设置了一个块,但知道我得到了一个错误:第 41 行的第 3 节课使用了 db 连接。
try-catchconstructorFatal error: Uncaught Error: Call to a member function prepare() on null in

php oop mysqli try-catch 抛出

评论

0赞 Dharman 5/16/2020
为什么你有所有这些 try-catch,为什么你抛出异常?
0赞 Dharman 5/16/2020
这永远不会是真的if(!$this->db)
0赞 Hmerman6006 5/16/2020
我正在类内检查数据库连接是否为假,如果是,则抛出没有可用连接的错误。我注意到我必须以某种方式将异常从类冒泡到类才能捕获它。__constructorWebApp()ConnectDB()WebApp()
0赞 Hmerman6006 5/16/2020
为什么永远不会是真的?该属性设置为 method 的返回值。如果返回值为 false,则不会为 true,即 ?if(!$this->db)$this->db$this->connector->connect()!$this->db$this->db === false
0赞 Dharman 5/16/2020
你杀死了你的脚本,这样它就不会返回 false。

答:

2赞 Dharman 5/16/2020 #1

看起来您误解了错误报告的想法。我会尽量向你澄清一般概念。

错误报告是为了通知开发人员错误的编码、错误和其他需要修复的潜在问题。错误报告不适用于产品用户。在开发时,您可以自己启用,但永远不要将其保留在代码中。但是,您应该始终记录错误。PHP有一个非常好的错误记录器,但我可以理解它对你来说可能还不够,你想记录更多的信息和错误消息。display_errors

您可以编写一个通用的错误处理程序,并捕获应用程序抛出的所有错误和异常,并使用您自己的记录器软件将其记录到服务器上的安全位置。不要在代码中间捕获异常。此类记录器需要位于应用程序的中心位置,并且位于单独的文件中,以便能够捕获所有错误。

出于这个原因,try-catch 不是很有用,因为你把它放在多个地方,并且它与你的应用程序代码交织在一起。此外,您只会捕获异常并忽略错误。你应该同时抓住两者。使用类似的东西来捕捉两者。catch(\Throwable $e)

@是一个错误抑制运算符。应不惜一切代价避免这种情况。如果你不能避免它,那么你需要重写代码来避免它。您在那里使用 mysqli 连接所做的事情实际上忽略了两次错误。首先,你使用,然后你杀死你的脚本。不要终止脚本。不要使错误静音。让你的错误冒出来,让它们被你的错误处理程序发现。@

如果你仔细想想,你的班级是相当无用的。要连接到数据库,您始终需要相同的 3 行。MySQLI 已经是一个类,因此在另一个类中换行 3 行是没有意义的。正确的代码应该无非是:ConnectDB

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$conn = new mysqli(DB_HOST, DB_USERRW, DB_PASSWRW, DB_DBASE);
$conn->set_charset('utf8mb4');

当 mysqli 无法连接时,您当前的脚本会退出,但即使您不使错误静音并且打开了错误报告,该变量也不可能为空。 成为另一个谬论。此外,当你刚刚静音时,你为什么要抛出一个例外?这让我想到了另一点。为什么要在立即捕获异常时抛出异常?当然,整个逻辑只不过是一个简单的 if 语句:if(!$this->db)

if(!$this->db) {
    $this->messager->erroutput([' Database connection is currently unavailable.']);
}

我看到你已经命名了你的类,我真的希望你不要向用户公开错误消息。这不仅是糟糕的用户体验,而且是一种安全风险。相反,您应该实现一个不错的 HTTP 500 错误页面,或者如果您的应用程序足够复杂,则应该实现您自己的错误页面,该页面将在错误处理程序捕获错误时显示。MessageOut

一旦发现某些错误,关闭mysqli错误报告没有任何意义。只需从代码中删除即可。mysqli_report(MYSQLI_REPORT_OFF);

为了直观地理解我所描述的内容,请考虑以下代码:

<?php

// ini_set('display_errors', 1);
ini_set('log_errors', 1);
error_reporting(E_ALL);

class WebApp {
    protected $db;

    function __construct() {
        $this->messager = new MessageOut();

        mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); // it can also be at the top of the script, but it makes more sense to put it together with the rest of mysqli code
        $this->db = new \mysqli(DB_HOST, DB_USERRW, DB_PASSWRW, DB_DBASE);
        $this->db->set_charset('utf8mb4');
    }

    public function selectIdata() {
        //select data
        $query = "SELECT *
                    FROM thetable";
        $stmt = $this->db->prepare($query);
        $stmt->execute();
        $stmt->store_result();

        $stmt->bind_result($idata);
        $result = [];
        while ($stmt->fetch()) {
            $result[] = $idata;
        }
        return $result;
    }
}

try {
    $app = new \WebApp();
} catch (\Throwable $e) {
    // log your errors here.
}

这不是完美的代码,因为错误处理程序不存在,它也应该位于单独的文件中,但总体思路是避免应用程序逻辑中不必要的代码。不要尝试捕捉。不要使错误静音,也不要添加无用的代码。保持简单。

评论

0赞 Hmerman6006 5/16/2020
谢谢你的回答。你提出了很多有效的观点,逻辑更加清晰。错误输出仅用于我的代码中的测试目的。那么,是否应该永远不要使用 try-catch 块来检查特定的错误代码并向用户输出自定义消息?例如,1062 重复条目。因为这就是我正在做的事情。当然不是像你这样严格有序的方法。但我正试图效仿类似的方法。ini_set('display_errors', 1); ini_set('log_errors',1); error_reporting(E_ALL); mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
0赞 Hmerman6006 5/16/2020
内置类前面的反斜杠是什么,即?\mysqli()
1赞 Dharman 5/16/2020
ini_set('log_errors',1); error_reporting(E_ALL); mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);即使在实时代码中,也应该存在于代码中。切勿向用户显示错误。仅当您知道如何从错误中恢复时,try-catch 才有用。如果出现重复输入,您知道发生这种情况时该怎么做,因此捕获和恢复是有意义的。只有当您知道为什么要这样做以及如何处理它时,才会捕获错误。不要养成在代码中使用 try-catch 的习惯。
1赞 Dharman 5/16/2020
反斜杠表示该类存在于全局命名空间中。没有必要,但始终指定完整命名空间是一种很好的做法。
0赞 Hmerman6006 5/16/2020
这就是解决我的问题的原因。正如您的回答中所述,我只听了异常 en 错误。在我的整个 php 项目中,我从未明确区分过这两者。这是一个非常有用的答案。catch(\Throwable $e)