创建数据库包装器不是一个好主意


Creating a database wrapper not a good idea?

我知道使用orm会更好,我计划将来使用它。但目前,我正在使用这样的结构:

带标题和日期的类Arcticle为数据库操作类DataArticle所以我不是在Article类中执行数据库操作,而是在一个单独的Data类中执行。

现在,在我的所有数据中。。我用代码执行数据库操作的类如下:

public function getArticle($id){        
        $query = "SELECT title,date from articles where id = ?";          
        if ($stmt = $this->database->getConnection()->prepare($query)) {            
            $stmt->bind_param('i',$id);
            $stmt->execute();
            $stmt->bind_result($title,$date);   
            $stmt->store_result();
            $stmt->fetch();         
            if(($stmt->num_rows) == 1){
                $article = new Article();
                $article->title = $title;
                $article->date = $date;
                $stmt->close();             
                return $article;
            }else{
                $stmt->close();
                return null;
            }           
        }else{          
            throw new Exception($this->database->getConnection()->error);
        } 
    }

但以这种方式工作意味着,在我的数据类中的每个函数中,我都会连接、执行一条语句并抛出错误。这是大量重复的代码,可以使用包装器进行集中处理。

现在,我遵循建议(在函数中抛出异常或如何进行下降错误处理)创建一个数据库包装器/处理程序来执行所有数据库内容,使其集中在一个类中,从而更容易维护。

所以我创建了这个类来开始使用PDO:

<?php
class DatabasePDO
{
    private $connection;
    private $host = "";
    private $username = "";
    private $password = "";
    private $dbname = "";
    public function openConnection(){
        $this->connection = new PDO("mysql:host=$this->host;dbname=$this->dbname",$this->username,$this->password);
        $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);     
    }
    public function getConnection(){
        return $this->connection;
    }
    public function closeConnection(){
        $this->connection = null;
    }
    public function insert($query, array $data){        
        $this->connection->prepare($query)->execute($data);     
        return $this->connection->lastInsertId();
    }
    public function update($query, array $data) {
        $stmt = $this->connection->prepare($query);
        $stmt->execute($data);
        return $stmt->rowCount();       
    }
    public function delete($query, array $data) {
        $stmt = $this->connection->prepare($query);
        $stmt->execute($data);
        return $stmt->rowCount();       
    }
    public function findOne($query, array $data = null){        
        $sth = $this->connection->prepare($query);
        if($data != null){
            $sth->execute($data);
        }else{
            $sth->execute();
        }       
        if($sth->rowCount() == 1){              
            return $sth->fetchObject();
        }else{
            return null;
        }
    }
    public function find($query, array $data = null){       
        $sth = $this->connection->prepare($query);
        if($data != null){
            $sth->execute($data);
        }else{
            $sth->execute();
        }
        if($sth->rowCount() > 0){
            while($res = $sth->fetchObject()){              
                $results[] = $res;
            }
            return $results;            
        }else{
            return null;
        }
    }
}
?>

但在阅读一些文章时,我发现这不是一个好的做法,因为PDO已经是一个数据库包装器了。

然而,by代码和以前一样可读性更强。现在它只是

public function getArticle($id){       
        $article = $this->database->find("select name, date from articles ?",array($id));       
        $article = new article($article->name, $article->date);
        return $article;
    }

这段代码要短得多,所有的数据库逻辑都在PDO包装器类中处理,否则我将不得不在每个函数中重复包装器的代码,并且我的代码将在很多地方而不是一个包装器中。

那么,有没有更好的方法来使用我的代码,或者这是我使用它的好方法。

不知道为什么要问或怀疑来自哪里,但创建数据库包装类是处理SQL查询的唯一正确方法。

尽管实现需要一些改进,但总体思想和用法几乎都很好。是的,将整个屏幕上的代码量减少到只有一行是这样一个类的主要好处之一。

说到改进-PDO有一些很好的技巧来缩短你的代码:

public function find($query, array $data = null){       
    $sth = $this->connection->prepare($query);
    $sth->execute($data);
    return $sth->fetchAll(); 
}

将以与您的版本完全相同的方式工作,但需要减少三倍的代码

从对创作敏感性的评论中回答您的问题,这样一个基于PDO的课程:
看,PDO已经是半DAL了。正如你所看到的,与mysqli相比,它已经有了很大的改进。虽然mysqli显然而且毫无疑问地需要在上面创建这样一个类,但PDO有许多开箱即用的必需功能。因此,确实可以使用原始PDO。而且很多a类都是在PDO上创建的,确实没用。但是,PDO也可以从一些改进中受益。

看,尽管我确实改进了您的PDO代码,将行数减少到只有三行,但基于mysqli的版本无法改进,并且需要所有几十行代码。所以,3行比十几行好,但find()函数的一行行仍然比三行好,不是吗?然而,总有更大的改进空间。你可以从我的标签维基中PDO失败的案例列表中得到一些想法。

存储数据库连接的更好方法是在singleton类中。

http://php.net/manual/de/language.oop5.patterns.php

<?php
class DatabasePDO
{
    private static $instance;
    private $connection;
    private $host = "";
    private $username = "";
    private $password = "";
    private $dbname = "";
    public static function getInstance()
    {
        if (!isset(self::$instance)) {
            self::$instance = new DatabasePDO();
        }
        return self::$instance;
    }
    public function openConnection(){
        $this->connection = new PDO("mysql:host=$this->host;dbname=$this->dbname",$this->username,$this->password);
        $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);     
    }
    public function getConnection(){
        return $this->connection;
    }
    public function closeConnection(){
        $this->connection = null;
    }
    public function insert($query, array $data){        
        $this->connection->prepare($query)->execute($data);     
        return $this->connection->lastInsertId();
    }
    public function update($query, array $data) {
        $stmt = $this->connection->prepare($query);
        $stmt->execute($data);
        return $stmt->rowCount();       
    }
    public function delete($query, array $data) {
        $stmt = $this->connection->prepare($query);
        $stmt->execute($data);
        return $stmt->rowCount();       
    }
    public function findOne($query, array $data = null){        
        $sth = $this->connection->prepare($query);
        if($data != null){
            $sth->execute($data);
        }else{
            $sth->execute();
        }       
        if($sth->rowCount() == 1){              
            return $sth->fetchObject();
        }else{
            return null;
        }
    }
    public function find($query, array $data = null){       
        $sth = $this->connection->prepare($query);
        if($data != null){
            $sth->execute($data);
        }else{
            $sth->execute();
        }
        if($sth->rowCount() > 0){
            while($res = $sth->fetchObject()){              
                $results[] = $res;
            }
            return $results;            
        }else{
            return null;
        }
    }
}
?>

使用此代码,您可以通过调用DatabasePDO::getInstance()->getConnection()从任何位置获取数据库连接;

public function getArticle($id){        
    $query = "SELECT title,date from articles where id = ?"; 
    $database = DatabasePDO::getInstance();
    if ($stmt = $database->getConnection()->prepare($query)) {            
        $stmt->bind_param('i',$id);
        $stmt->execute();
        $stmt->bind_result($title,$date);   
        $stmt->store_result();
        $stmt->fetch();         
        if(($stmt->num_rows) == 1){
            $article = new Article();
            $article->title = $title;
            $article->date = $date;
            $stmt->close();             
            return $article;
        }else{
            $stmt->close();
            return null;
        }           
    }else{          
        throw new Exception($database->getConnection()->error);
    } 
}