Php 在PDO中使用数据库类

Php 在PDO中使用数据库类,php,mysql,pdo,database-connection,Php,Mysql,Pdo,Database Connection,经典的《第一班轮》也看到过类似的问题,但没有一个能真正帮助我理解我所处的十字路口 代码之前有一点背景知识-我对PHP或PDO并不陌生(虽然也不是专家),但我对面向对象PHP完全是新手,我正试图在何时使用类和何时可能过度使用类之间取得平衡 我希望答案分为两部分。首先,在将PDO用于连接、基本查询等时,创建包装器数据库类是一个很好的实践 第二,如果没有,有没有更好的方法来加速查询编写 编辑当我对下面的代码提出疑问时,实际上我对PDO包装类的总体方法提出了疑问-因此下面的类可能比这个大得多,但有什么需

经典的《第一班轮》也看到过类似的问题,但没有一个能真正帮助我理解我所处的十字路口

代码之前有一点背景知识-我对PHP或PDO并不陌生(虽然也不是专家),但我对面向对象PHP完全是新手,我正试图在何时使用类和何时可能过度使用类之间取得平衡

我希望答案分为两部分。首先,在将PDO用于连接、基本查询等时,创建包装器数据库类是一个很好的实践

第二,如果没有,有没有更好的方法来加速查询编写

编辑当我对下面的代码提出疑问时,实际上我对PDO包装类的总体方法提出了疑问-因此下面的类可能比这个大得多,但有什么需要/好处吗

参见下面的代码; 注意:通过config.php中的spl_autoload_register()调用类文件

class_database.php

class Database
{
    private $conn;

    public function __construct() {
        $this->openConnection();
    }

    public function openConnection() {
        try {
            $this->conn = new PDO('mysql:host=' . DB_SERVER . '; dbname=' . DB_NAME, DB_USER, DB_PASS);
            $this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch (PDOException $e) {
            echo 'There was an error connecting to the database, Error: ' . $e->getMessage();
            die();
        }
    }

    public function getAll($sql, array $params) {
        $stmt = $this->conn->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    }
}
require_once '../includes/config.php';
$dbh = new Database();

$sql = ("SELECT * FROM users where id = :id and username = :username");
$id = 1;
$username = 'craig';
$params = array(':id' => $id,
                ':username' => $username);
$row = $dbh->getAll($sql, $params);
var_dump($row);
generic_file.php

class Database
{
    private $conn;

    public function __construct() {
        $this->openConnection();
    }

    public function openConnection() {
        try {
            $this->conn = new PDO('mysql:host=' . DB_SERVER . '; dbname=' . DB_NAME, DB_USER, DB_PASS);
            $this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch (PDOException $e) {
            echo 'There was an error connecting to the database, Error: ' . $e->getMessage();
            die();
        }
    }

    public function getAll($sql, array $params) {
        $stmt = $this->conn->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    }
}
require_once '../includes/config.php';
$dbh = new Database();

$sql = ("SELECT * FROM users where id = :id and username = :username");
$id = 1;
$username = 'craig';
$params = array(':id' => $id,
                ':username' => $username);
$row = $dbh->getAll($sql, $params);
var_dump($row);
现在,对我来说,这似乎毫无意义。单独使用PDO,而不是包装器类,这个查询编写起来同样简单。除此之外,如果我想使用不同的获取方法,我必须在类中编写更多的方法。 此外,之前我使用了一个简单的函数来实例化并返回一个新的PDO对象,只需包含该文件并为函数返回赋值一个变量就简单得很——同样,我觉得类方法太简单了

此外,使用上面的代码,并在类中执行此操作,我是否没有失去“准备”语句的好处,因为每次都必须传递sql语句,甚至只是为了更改同一语句的变量

然而,我在网上找到了很多数据库包装类的例子,尤其是在我目前使用的Lynda.com上。最重要的是,我不是专家,因此我觉得过度杀戮可能是最好的做法,并强烈推荐,因此期待你们这些专家来帮助我

那么,回到我的问题上来——在使用PDO时,有没有充分的理由使用这样的类? 如果没有,是否有其他人用来最小化使用PDO查询所需的代码行的另一种干法


提前谢谢。

我曾经有过你同样的问题

将数据库抽象出来的好处是,可以确保所有连接都正确建立,如果确实需要更改数据库类型,则只需更改其中一个位置的代码。它还使检查发出的查询变得更容易,因为您知道,如果在类中回显并退出,所有查询都将能够被检查

我解决这个问题的方法是创建一个类,构造函数在其中建立连接并将其分配给一个私有变量,同时也在数据库中设置表。 最好的方法是使用一些公共函数来创建、检索、更新和删除。这有时被称为积垢。 对于每个函数,唯一的第一个参数是数组。为了创建它,需要数组并用它创建一个准备好的语句,然后执行它。 它与其他函数的作用非常相似,但对于检索数组,它是匹配的;对于更新,它获取以id结尾的内容,并在id=提供的位置将其余内容设置为update;对于delete,它删除表中所有键=值的位置

编辑: 这是我放在类中的delete函数。如果参数值之一是数组,它将准备语句并循环执行。这只是一个变量的变化。您也可以在其中传递一个数组,其中数值索引的值是您想要插入的数组,尽管这不是我设置代码的方式

public function delete($info) {
    $dbh = $this->dbh;

    if (isset($info['submit_action'])) unset($info['submit_action']);
    $where = array();
    foreach (array_keys($info) as $name) {
        $where[] .= "$name = :$name";
    }
    //echo "DELETE FROM {$this->table_name} WHERE " . implode(" AND ", $where) . ";"; exit;
    $data = $dbh->prepare("DELETE FROM {$this->table_name} WHERE " . implode(" AND ", $where) . ";");
    foreach ($info as $name => $value) {
        if ($array_value == $name) $data->bindParam(":$name", $array_info);
        else $data->bindValue(":$name", trim($value));
    }

    foreach ($info as $name => $value) if (is_array($value)) { $array_value = $name; break; }
    if (isset($array_value)) {

        foreach ($info[$array_value] as $array_info) {
            try {
                $data->execute();
            }
            catch (PDOException $e) {
                if (!is_null($this->error_msg))
                    handle_error($this->error_msg, $e->getMessage());
                else
                handle_error("There was a problem removing the {$this->subject}.", $e->getMessage());
            }
        }

    } else {
        try {
            $data->execute();
        }
        catch (PDOException $e) {
            handle_error(/*public error msg - could set this anyway you want*/, $e->getMessage());
        }
    }

    // Send success msg
}

我个人认为PDO足够薄,可以不用包装器来使用。PDO本身就是一个数据库抽象类,所以我同意你的想法,它只提供了额外的复杂性,可以将它包装到另一个公开几乎相同api的类中。这样做的唯一真正动机是,如果你打算将数据库抽象到你可以为你的类提供一个模拟来进行单元测试。像Doctrine DBAL这样的库在PDO的基础上添加了一些有用的东西,但是像你例子中这样一个简单的包装器并没有提供任何东西。这个问题没有明确的对错答案。这在很大程度上取决于你的环境和个人意见。因此,这是离题了。太好了,有道理了,谢谢。如果说它只需要一个数组,那么sql语句呢?将sql设置为类级别不是太死板了吗?或者你是指最流行的查询,那么你会在文件中从头开始编写一些更模糊的查询,而不是每次都使用该类吗?另一点——我上面的代码,通过在类中这样做,我是否正在失去“准备”语句的好处,因为每次都必须传递sql语句,甚至只是为了更改同一语句的变量?