【问题标题】:Creating a database wrapper not a good idea?创建数据库包装器不是一个好主意?
【发布时间】:2013-08-24 18:13:56
【问题描述】:

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

带有标题和日期的北极类 数据库操作的 DataArticle 类 所以我没有在我的文章类中执行我的数据库操作,而是在一个单独的数据类中。

现在,在我所有的 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);
        } 
    }

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

现在我按照建议 (Throw an exception in a function or how to do descent error handling) 创建一个数据库包装器/处理程序来执行所有数据库内容,因此它们都集中在一个类中,这样更易​​于维护。

所以我创建了这个类来开始使用 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 已经是一个数据库包装器。

但是,通过代码比以前更具可读性。 现在只是

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 包装器类中处理,否则我将不得不在每个函数中重复包装器的代码,我的代码将出现在很多地方而不是一个包装器中。

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

【问题讨论】:

    标签: php pdo wrapper


    【解决方案1】:

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

    虽然实现需要一些改进,但总体思路和用法几乎都非常出色。是的,将整个屏幕的代码量减少到一行是此类的主要好处之一。

    谈到改进 - PDO 有一些很好的技巧可以缩短您的代码:

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

    工作方式与您的版本完全相同,但代码量少三倍

    回答 cmets 关于创建这样一个基于 PDO 的类的敏感性的问题:
    看,PDO 已经是一个半 DAL。可以看到,相比mysqli已经是很大的进步了。虽然 mysqli 显然而且无疑需要在其上创建这样一个类,但 PDO 具有许多开箱即用的必需特性。因此,确实可以使用原始 PDO。许多在 PDO 上创建的类,确实没用。但是,PDO 也可以从一些改进中受益。

    看,虽然我确实改进了你的 PDO 代码,将行数减少到只有三行,但基于 mysqli 的版本无法改进,需要全部几十行代码。所以,3 行优于 12 行,但 find() 函数的 1 行仍优于 3 行,不是吗?然而,总有一些更大的改进空间。您可以从我的标签 wiki 中的List Of The Cases Where PDO Fails 获得一些想法。

    【讨论】:

    • 我对这篇文章感到困惑:codereview.stackexchange.com/questions/29362/…,包装器看起来很像我的。所以我开始怀疑使用我的包装器是否是一种好习惯?感谢您的改进,仍然停留在 mysqli 思维和习惯 PDO 的方便性:)
    • 感谢更新,我明白了。但我不清楚为什么我的包装器没问题,而我提供的链接中的包装器不是因为它们非常相似。是不是因为我的组合用于存储和检索实体。因为我可以理解,单独使用包装器确实是不必要的,并且删除了功能。只是想知道我是否走在正确的轨道上:)
    • 好的,看了一眼那堂课。没关系,除了那些我觉得无用且不灵活的插入/更新/删除功能。那里的大多数评论者都不知道。一个类是封装很多有用的东西并同时避免重复的好东西:查询日志记录。查询分析。额外的占位符支持。获取各种数据的辅助函数。是的,PDO 支持其中一些功能。这就是为什么我称它为“半 DAL”。但它仍然可以从包装器中受益很多。一个说“PDO 尽善尽美”的人只是没有想象力(也没有经验)
    【解决方案2】:

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

    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);
        } 
    }
    

    【讨论】:

    • 你完全错过了这门课的目的。
    • 我真的不想为我的数据库使用单例,但这是另一个讨论。
    猜你喜欢
    • 1970-01-01
    • 2012-01-09
    • 2011-02-03
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 2011-05-14
    • 1970-01-01
    • 2014-10-03
    相关资源
    最近更新 更多