Simple PDO wrapper(简单的 PDO 包装器)
问题描述
我的 Web 应用程序目前确实执行了简单的查询:简单的 CRUD 操作、计数、...
My web application currently has do execute simple queries: simple CRUD operations, counting,...
几个月前,有人推荐我在这里为此编写一个简单的 PDO 包装器(以避免每次应执行查询时编写 try/catch、prepare()、execute() 等).显示了此示例方法(我进行了一些更改,以便可以在我自己的项目中使用它):
A few months ago, someone recommended me here to write a simple PDO wrapper for this (to avoid writing try/catch, prepare(), execute(), etc. each time a query should be executed). This example method was shown (I've made some changes so I could use it in my own project):
public function execute() {
    $args  = func_get_args();
    $query = array_shift($args);
    $result = false;
    try {
      $res = $this->pdo->prepare($query);
      $result = $res->execute($args);
    } catch (PDOException $e) { echo $e->getMessage(); }
    return $result;
  }
由于我需要执行更多操作(执行查询、检索 1 条记录、检索多条记录、计算结果),我为所有这些操作创建了一个方法:
As I need to perform more operations (executing queries, retrieving 1 record, retrieving multiple records, counting results) I created a method for all of these:
  public function getMultipleRecords() {
    $args  = func_get_args();
    $query = array_shift($args);
    $records = array();
    try {
      $res = $this->pdo->prepare($query);
      $res->execute($args);
      $records = $res->fetchAll();
    } catch (PDOException $e) { echo $e->getMessage(); }
    return $records;
  }
  public function getSingleRecord() {
    $args  = func_get_args();
    $query = array_shift($args);
    $record = array();
    try {
      $res = $this->pdo->prepare($query);
      $res->execute($args);
      $record = $res->fetch();
    } catch (PDOException $e) { echo $e->getMessage(); }
    return $record;
  }
  public function execute() {
    $args  = func_get_args();
    $query = array_shift($args);
    $result = false;
    try {
      $res = $this->pdo->prepare($query);
      $result = $res->execute($args);
    } catch (PDOException $e) { echo $e->getMessage(); }
    return $result;
  }
  public function count() {
    $args  = func_get_args();
    $query = array_shift($args);
    $result = -1;
    try {
      $res = $this->pdo->prepare($query);
      $res->execute($args);
      $result = $res->fetchColumn();
    } catch(PDOException $e) { echo $e->getMessage(); }
    return $result;
  }
如您所见,大部分代码是相同的.每种方法只有 2 行代码不同:$result 的初始化(我总是想返回一个值,即使查询失败)和获取.我可以不使用 4 种方法,而是只编写其中一种并传递一个带有操作类型的额外参数.这样,我可以使用 switch 语句的一堆 if/else 语句.但是,我认为代码可能会变得混乱.这是解决这个问题的好方法吗?如果没有,有什么好的解决办法?
As you see, most of the code is the same. Only 2 lines of code are different for each method: the initialisation of $result (I always want to return a value, even if the query fails) and the fetching. Instead of using 4 methods, I could write just one of them and pass an extra parameter with the type of action. That way, I could use a bunch of if/else statements of a switch statement. However, I think the code can get messy. Is this a good way for solving this problem? If not, what would be a good solution to it?
我遇到的第二个问题(这就是我现在正在研究这个类的原因)是我想将准备好的语句与 LIMIT SQL 语句一起使用.但是,这是不可能的:
The second problem I have (which is why I'm working on this class right now) is that I want to use prepared statements with the LIMIT SQL statement. However, it is not possible to do this:
$res = $pdo->prepare("SELECT * FROM table LIMIT ?");
$res->execute(array($int));
由于某种原因,变量将被引用(因此查询将失败),如下所述:https://bugs.php.net/bug.php?id=40740
The variabele will be quoted for some reason (and so the query will fail), as explained here: https://bugs.php.net/bug.php?id=40740
解决方案似乎使用 bindValue() 并使用 int 数据类型作为参数:http://www.php.net/manual/de/pdostatement.bindvalue.php
The solution seems to use bindValue() and use the int datatype as a parameter: http://www.php.net/manual/de/pdostatement.bindvalue.php
我可以重写方法来支持这一点,但我还需要使用一个额外的参数.我不能再使用 $db->execute($sql, $variable1, $variable2); 因为我需要知道数据类型.
I could rewrite the method(s) to support this, but I would also need to use an extra parameter. I can't just use $db->execute($sql, $variable1, $variable2); anymore as I need to know the data type.
解决这个问题的最佳方法是什么?
What's the best way to solve this?
谢谢
推荐答案
如何使用可以链接的方法创建一个类(为了清楚起见,我已经删除了错误检查):
How about creating a class with methods that you can chain (for clarity, I've removed error checking):
class DB {
    private $dbh;
    private $stmt;
    public function __construct($user, $pass, $dbname) {
        $this->dbh = new PDO(
            "mysql:host=localhost;dbname=$dbname",
            $user,
            $pass,
            array( PDO::ATTR_PERSISTENT => true )
        );
    }
    public function query($query) {
        $this->stmt = $this->dbh->prepare($query);
        return $this;
    }
    public function bind($pos, $value, $type = null) {
        if( is_null($type) ) {
            switch( true ) {
                case is_int($value):
                    $type = PDO::PARAM_INT;
                    break;
                case is_bool($value):
                    $type = PDO::PARAM_BOOL;
                    break;
                case is_null($value):
                    $type = PDO::PARAM_NULL;
                    break;
                default:
                    $type = PDO::PARAM_STR;
            }
        }
        $this->stmt->bindValue($pos, $value, $type);
        return $this;
    }
    public function execute() {
        return $this->stmt->execute();
    }
    public function resultset() {
        $this->execute();
        return $this->stmt->fetchAll();
    }
    public function single() {
        $this->execute();
        return $this->stmt->fetch();
    }
}
然后您可以像这样使用它:
You can then use it like this:
// Establish a connection.
$db = new DB('user', 'password', 'database');
// Create query, bind values and return a single row.
$row = $db->query('SELECT col1, col2, col3 FROM mytable WHERE id > ? LIMIT ?')
   ->bind(1, 2)
   ->bind(2, 1)
   ->single();
// Update the LIMIT and get a resultset.
$db->bind(2,2);
$rs = $db->resultset();
// Create a new query, bind values and return a resultset.
$rs = $db->query('SELECT col1, col2, col3 FROM mytable WHERE col2 = ?')
   ->bind(1, 'abc')
   ->resultset();
// Update WHERE clause and return a resultset.
$db->bind(1, 'def');
$rs = $db->resultset();
如果您愿意,您可以更改 bind 方法以接受数组或关联数组,但我发现此语法非常清晰 - 它避免了必须构建数组.参数类型检查是可选的,因为 PDO::PARAM_STR 适用于大多数值,但请注意传递空值时的潜在问题(请参阅 PDOStatement->bindValue 文档中的注释).
You could alter the bind method to accept an array or associative array if you prefer, but I find this syntax quite clear - it avoids having to build an array.  The parameter type checking is optional, as PDO::PARAM_STR works for most values, but be aware of potential issues when passing null values (see comment in PDOStatement->bindValue documentation).
这篇关于简单的 PDO 包装器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:简单的 PDO 包装器
				
        
 
            
        基础教程推荐
- php 7.4 在写入变量中的 Twig 问题 2022-01-01
 - 将变量从树枝传递给 js 2022-01-01
 - PHPUnit 的 Selenium 2 文档到底在哪里? 2022-01-01
 - php中的foreach复选框POST 2021-01-01
 - Yii2 - 在运行时设置邮件传输参数 2022-01-01
 - 如何在数学上评估像“2-1"这样的字符串?产生“1"? 2022-01-01
 - 主题化 Drupal 7 的 Ubercart “/cart"页 2021-01-01
 - php中的PDF导出 2022-01-01
 - Web 服务器如何处理请求? 2021-01-01
 - 使用 scandir() 在目录中查找文件夹 (PHP) 2022-01-01
 
    	
    	
    	
    	
    	
    	
    	
    	
				
				
				
				