在函数中抛出异常或如何进行下降错误处理

时间:2013-08-15 08:52:55

标签: php exception mysqli prepared-statement

我目前正在使用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没有。 你必须自己检查而不是扔掉它。 假设我使用databasewrapper并将其命名为:

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

此方法中的某处出现$ stmt-> execute。我应该检查它是否成功并抛出异常或者我是否应该在此处触发错误?

因为你建议使用error_handler。

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

更新2

  1. ajax怎么样?我使用JSON返回结果。如果出现错误,我应该使用try catch在这里返回json.success true还是false?或者我该如何处理错误?

  2. 如果我想显示更具体的信息怎么办? 例如:当用户执行注册并使用已经注册的用户名和/或电子邮件时,会抛出错误,因为违反了唯一键。 但我不只是想显示“嘿发生500错误”,因为在这种情况下,重要的是registrator知道问题是什么,比如“这个用户名被采取了”,......

    在这些情况下,尝试捕获是一种很好的做法是正确的,因为您想要显示详细信息吗?

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

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

2 个答案:

答案 0 :(得分: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);

难道你没有找到这段代码,被添加到每个查询执行中,这又是一个多余的代码?你真正需要的是database handler class做所有肮脏的工作。

看看这个函数是什么样的:

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

所有数据库操作的两行。

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

答案 1 :(得分:1)

我同意Serenarules的说法:“使用例外来通知用户某些方法失败是效率低下的”。 它没用:错误消息将在错误日志中找到。用户可以用这些细节做些什么?在大多数情况下,“错误500”已经足够了。

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