PHP在类中没有抛出指定的错误信息

问题描述 投票:0回答:1

我有三个类,每个类在连接到我的数据库时处理不同的功能。类1的名称是 ConnectDB() 其中处理 MySqli() 连接;第2类,名称为 MessageOut() 它通过一个 $_SESSION['message'] 鍵到用戶界面和第3類,名稱為 WebApp() 使用MySqli连接从数据库中获取数据并将其传递给UI。这与我平时做数据库连接、收集和显示的方式不同。 通常我只是在三个文件中创建了很多函数,如果需要的话就调用它们。 但是我的网站越来越大,越来越复杂,所以我正在重新组织一切。我目前的问题是,当我在第3类中创建db连接时,它没有抛出我编程的错误。

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定义的密码改成了错误的密码,并加载了文件,但是在我的第1类中的第10行出现了错误,尽管错误被抑制了。 我的想法是在使用前检查连接。我怎样才能在我的第3类中得到 "数据库连接当前不可用 "的错误信息?编辑 于是,我重新评估了我所做的事情,并设定了一个。try-catch 块内 constructor 的第3类,但我知道我得到一个错误。Fatal error: Uncaught Error: Call to a member function prepare() on null in 第3个类在第41行使用db连接。

php oop mysqli try-catch throw
1个回答
2
投票

看来你误解了错误报告的概念。我将尝试向你澄清一般的概念。

错误报告是为了通知开发人员错误的编码,错误和其他需要修复的潜在问题。错误报告不是针对产品的用户。当你在开发时,你可以启用 display_errors 但你绝对不应该把它留在代码中。然而你应该总是记录错误。PHP 有一个非常好的错误记录器,但我可以理解它可能对你来说是不够的,你想记录更多的信息和错误信息。

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

出于这个原因,你的try-catch并不是很有用,因为你的try-catch不止在一个地方,而且它与你的应用程序代码交织在一起。另外,你只捕获了异常和无视错误。你应该同时捕捉这两个异常。使用类似 catch(\Throwable $e) 来捕捉两者。

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

如果你仔细想想,你的类 ConnectDB 是非常无用的。mysqli已经是一个类了,所以在另一个类中封装3行代码是没有意义的。正确的代码应该是这样的:当mysqli无法连接时,你当前的脚本退出。

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(!$this->db) 变成了另一个谬论。另外,你刚刚沉默了一个异常,为什么还要抛出一个异常呢?这让我想到了另一个问题。当你立即捕捉到一个异常时,为什么要抛出一个异常呢? 当然,那里的整个逻辑不过是一个简单的if语句。

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

我看到你把你的类命名为 MessageOut 而且我真的希望你不要把错误信息暴露给用户。这不仅是糟糕的用户体验,也是一个安全风险。你应该实现一个漂亮的HTTP 500错误页面,或者如果你的应用程序足够复杂,你自己的错误页面将在你的错误处理程序捕获错误时显示。

一旦发现错误就关闭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.
}

这不是完美的代码,因为错误处理程序不在那里,而且它也应该在一个单独的文件中,但总的想法是避免在你的应用逻辑中出现不必要的代码。不要try-catch。不要对错误进行沉默,不要添加没有任何作用的代码。保持简单。

© www.soinside.com 2019 - 2024. All rights reserved.