【问题标题】:Should I throw Exceptions in own Database class with PDO?我应该使用 PDO 在自己的数据库类中抛出异常吗?
【发布时间】:2015-11-14 18:44:49
【问题描述】:

嘿,我有带 PDO 的数据库类和面向对象论坛的其他一些类:

class Database {

    private $databaseConnection;

    function __construct($path = "", $dbUsername = "", $dbPassword = ""){
        $parts = explode('.',$path);
        $documentType = array_pop($parts);

        if(($path == "") || ((strcmp($documentType, "sq3") !== 0) && (strcmp($documentType, "sqlite") !== 0))) {
            throw new Exception("The Database must bee .sq3 or .sqlite and Path must be stated");
        }

        $this->databaseConnection = new PDO('sqlite:' . $path, $dbUsername, $dbPassword);
        $this->databaseConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $this->databaseConnection->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

        self::query('CREATE TABLE...)');
    }

    function query($sql, $params = NULL){
    ...
    }

    function getObjects($objectTable, $searchedForAttribute, $attributeValue){
    ...
    }


    function insertObject($object){
    ...
    }

    function updateObject($object){
    ...
    }

    function removeObject($object){
    ...
    }

    ...//some other methods

    function __destruct(){
        unset($this->databaseConnection);
    }
}

我应该使用例外吗?比如:

    function insertObject($object){
    try {
       ...
    }catch(PDOException $e){
            throw new Exception($e->getMessage());
         }
    }

因此,我必须在其他地方捕获此异常并以不同的方式将其发送出去。例如:我有一个类用户和一个表用户。因此,如果填写了新注册,我必须验证新用户的信息。因此,如果一个扩展用户选择了一个已经在数据库中的名称,我会抛出一个异常,尽管我只需要一条消息给用户,说明该名称已经分配。

所以我认为如果我这样做会更好:

    function insertObject($object){
    try {
       ...
    }catch(PDOException $e){
            return "Username already assigned";
         }
    }

当然,我并不总是知道为什么会抛出异常,但在这种情况下,我会使用 if 块来验证数据。

那么在这种情况下我应该如何使用异常处理呢?

【问题讨论】:

    标签: php mysql exception pdo


    【解决方案1】:

    我应该使用例外

    绝对是的。这是唯一的方法。

    比如:

    }catch(PDOException $e){
            throw new Exception($e->getMessage());
         }
    

    进行这样的重新投掷绝对没有意义。你为什么不直接离开 PDOException 呢?

    我应该使用 PDO 在自己的数据库类中抛出异常吗?

    是的,你应该这样做。

    那么在这种情况下我应该如何使用异常处理呢?

    你必须先了解两件事。

    1. 例外情况不同。那是故意的。是的,您可以将异常用于运行时错误和用户验证。但这将是不同的例外,具有完全不同的处理方式
    2. 任何数据库处理类都不应该验证用户数据。那是不同的课程。

    对于运行时异常(如查询失败),不需要太多处理。编写一个通用的异常处理程序,该处理程序执行一些常见的工作,即记录消息并显示借口页面。当然,不应向用户显示任何真正的错误消息。只是一个常见的借口。

    但是对于用户验证,请使用 try..catch 通过捕获您自己的 UserValidationException 来查看是否所有数据都已正确验证。

    换句话说,程序员有例外,用户有例外。你必须以不同的方式对待他们。 “数据库必须是 .sq3 或 .sqlite 并且必须说明路径”是程序员的一种,不应向用户显示。相反,它必须被记录以供程序员参考,必须向用户显示一个借口页面并且必须停止程序。

    “用户名已被占用”是用户名,必须向他们显示。

    要区分这两种类型的异常,必须使用不同的异常类。

    这两种类型可能遇到的唯一情况是来自数据库的某些错误,可用于验证目的。在这种情况下,必须实现一个条件块,如另一个答案所示。

    但是,异常可能不方便验证用户输入,因为您可能希望收集所有可能的错误,而不是一个。在这种情况下,不要使用异常进行数据验证,而是一个接一个地运行验证并将错误添加到数组中。

    【讨论】:

      【解决方案2】:

      您的问题很简单,但同时又非常庞大(恕我直言)。

      首先,如果您想要“通过 ORM/模型进行简单的数据库抽象”,我建议您使用 Doctrine 或其他好的现成 ORM 包。或者一个框架。

      如果(像我一样)你真的很喜欢像这样从头开始做事,那么我从过去的痛苦经历中得到一些建议。

      1. 返回字符串(就像您在问题末尾建议的那样)是一个非常糟糕的主意(TM)。字符串适用于字符串的东西 - 不是像这样定义从一段代码到另一段代码的响应。定义的常量(例如,使用整数值)更适合这条路线 - 恕我直言。
      2. 例外在这里很有意义 - 你想说“我没有按照你的要求去做,我需要你来处理它”。

      如果您选择走异常路线(我都是专业人士 - 最初来自 C/C++ 背景)使用字符串值作为字符串位(为异常提供一条人性化的消息以显示)并提供它也是一个机器友好的属性(对于将捕获它的代码)。

      \PDOException 很自然地可以说明数据库故障 刚刚发生,例如“我失去连接”或“MySQL 中断”。您可能希望让这些异常自行返回到调用您的代码...

      对于特定于模型的错误,我会创建适当的异常类。字面意思:

      class UserModelException extends \Exception {
       ... // Optional stuff here
      }
      

      然后你可以在调用代码中捕捉到不同的分类错误:

      try {
       ...
      } catch (\UserModelException $e) {
       ...
      } catch (\PDOException $e) {
       ...
      }
      

      等等

      当然,您可能希望在模型中捕获 PDO 异常,以确定唯一键约束之类的东西是否刚刚爆炸 - 即表明用户名已经存在。在这种情况下,您可能(在您的模型中)想要:

      try {
       ...
      } catch (\PDOException $e) {
         if (...) { // unique constraint error - username already taken
            throw new \UserModelException(...);
         } else {
            throw $e;
         }
      }
      

      这是否有意义,是否有任何帮助?

      我想不出(在我脑海中)我建议抛出一个文字 \Exception 对象的情况 - 我总是在每个上下文的基础上继承它。

      【讨论】:

      • 是的,现在我知道如何使用和处理异常了。也非常感谢您澄清第二个答案。
      猜你喜欢
      • 2013-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-28
      相关资源
      最近更新 更多