1

我目前正在使用 MySQLi 准备好的语句来处理我的数据库。因为 MySQLi 准备好的语句只在连接错误时抛出错误,所以我不得不自己检查错误并自己抛出错误。在 PDO 中(我将在未来使用它,因为我现在确信它工作得更好)可能会有更好的错误处理,因为 PDO 确实会按预期抛出错误,您可以使用 PDOException 捕获这些错误。

但是现在,我坚持使用 MySQLi,所以我想知道我当前的代码是否是好的做法?在很多教程和书籍中,我可以找到类似的工作流程,但是在某些地方我读到“使用异常通知用户某些方法失败是低效的,并且被认为是不好的做法”。(http://www.sitepoint.com/forums/showthread.php?872057-should-i-use-1-or-many-try-catches-in-a-page-that-uses-PDO

try{
    $user = $dataUser->getById(1);
}catch(UserNotFoundException $unfe){
    echo 'No user found with the provided id';
}catch(Exception $exc){
    //do some logging with the real exception
    ...
    //show a readable error to the website visitor
    echo "There was an error retrieving the user from the database.";
}

In my function I use something like this:
function getById($id){
    $query = "select user_id, username,firstname from users where user_id = ?";
    if ($stmt = $this->database->getConnection()->prepare($query)) {
        $stmt->bind_param('i',$id);
        if($stmt->execute()){
                throw new exception('There was an error retrieving the user by id: ' . $stmt->error);
        }
        $stmt->bind_result($userId,$username);      
        $stmt->store_result();
        $stmt->fetch();                                             
        if(($stmt->num_rows) == 1){
            $stmt->close();         
        $user = new User($username);
        $user->userId = $userId;
        $user->username = $username;
        return $user;               
        }else{
            $stmt->close();
        throw new UserNotFoundException("No user found matching the id.");
        }
    }else{          
        throw new Exception("There was a database error retrieving the user by id: " .    $this->database->getConnection()->error);
    }
}

更新 1基于“你的常识”的评论

mysqli_report(MYSQLI_REPORT_ALL);没那么好用。。

我已经做了一些练习,但我仍然不清楚异常和错误之间的区别到底是什么。当我使用 PDO 时,我会在执行失败时抛出异常。mysqli 没有。你必须自己检查而不是扔掉它。假设我使用数据库包装器并将其称为:

  $this->db->getOne($query,'id');

在这个方法的某个地方 $stmt->execute 出现了。我应该检查它是否成功并抛出异常还是应该在这里触发错误?

因为您建议使用error_handler。

这让我很困惑,因为如果我使用 pdo,我应该使用 exception_handler 对吗?

更新 2

  1. 阿贾克斯呢?我使用 JSON 返回结果。如果出现错误,我应该在这里使用 try catch 来返回 json.success 是真还是假?或者我应该如何处理这里的错误?

  2. 如果我想显示更具体的信息怎么办?例如:当用户执行注册并使用已注册的用户名和/或电子邮件时,由于违反了唯一密钥,将引发错误。但我不只是想显示“嘿,发生了 500 错误”,因为在这种情况下,注册者知道问题所在很重要,例如“此用户名已被占用”,...

    那么在这些情况下,try catch 是一种很好的做法是否正确,因为您想显示详细信息?

我只是对何时使用 try catch 以及何时让全局错误处理程序为我处理错误感到困惑。在这个主题中,我读到了这个:

“您可以使用 set_exception_handler() 在您的自定义函数中处理未捕获的异常。但是,“正确”的方式是让您尝试......例如在执行查询时捕获异常,并使用您的自定义函数记录相应地。” 但这在本主题中被认为是不好的做法。

4

2 回答 2

1

如果我当前的代码是好的做法?

不,在很多方面。

首先,mysqli最后管理了这个异常的东西。

mysqli_report(MYSQLI_REPORT_ALL);

会告诉mysqli 抛出异常。然而,

使用异常通知用户某些方法失败是低效的,被认为是不好的做法

确切地。终于有人聪明到可以反驳所有这些无用的教程和书籍。

//do some logging with the real exception

因为您的应用程序中的每个查询都是相当...多余的。你不觉得吗?然而,

//show a readable error to the website visitor

不是那么“可读”。是的,它是简单的英语。但是站点访问者与数据库有什么关系呢?什么用户?什么是“检索”?所有这些东西都是无用的和令人困惑的。请看看一些专业建造的网站,例如这个。它们不会给您带来任何技术细节的负担,只显示一个通用的 500 错误页面。

并且不必针对您在代码中执行的每个操作执行此操作,而是使用 set_error_handler() 进行集中处理。

而异常只能用于处理错误本身。

所以,你的 try..catch 块是完全多余的。如果出现错误,错误处理程序必须捕获异常,记录错误并显示通用 500 错误页面。

throw new exception('There was an error retrieving the user by id: ' . $stmt->error);

您是否没有发现这段代码被添加到每个查询执行中,又是一个非常多余的东西?您真正需要的是一个数据库处理程序类来完成所有肮脏的工作。

看看这个函数的样子:

function getById($id)
{
    $query = "select username from users where user_id = ?";
    $name  = $this->db->getOne($query,$id);
    return new User($name);
}

所有数据库操作的两行。

(但是您创建 User 类的想法很奇怪)

于 2013-08-15T09:06:50.843 回答
1

我同意 Serenarules 的说法:“使用异常通知用户某些方法失败是低效的”。没用:错误信息会在错误日志中找到。用户可以用这些细节做什么?在大多数情况下,“错误 500”就足够了。

数据库连接 KO 是一个应该引发异常的真正问题。但我个人认为“没有找到与 id 匹配的用户”的情况。不应该出现任何异常。相反,这种情况应该只是改变应用程序的行为。除非您想在错误日志中收听这些事件?

于 2013-08-15T09:20:59.430 回答