简单的 PDO 包装器

Simple PDO wrapper(简单的 PDO 包装器)
本文介绍了简单的 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 包装器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

本站部分内容来源互联网,如果有图片或者内容侵犯了您的权益,请联系我们,我们会在确认后第一时间进行删除!

相关文档推荐

DeepL的翻译效果还是很强大的,如果我们要用php实现DeepL翻译调用,该怎么办呢?以下是代码示例,希望能够帮到需要的朋友。 在这里需要注意,这个DeepL的账户和api申请比较难,不支持中国大陆申请,需要拥有香港或者海外信用卡才行,没账号的话,目前某宝可以
PHP通过phpspreadsheet导入Excel日期,导入系统后,全部变为了4开头的几位数字,这是为什么呢?原因很简单,将Excel的时间设置问文本,我们就能看到该日期本来的数值,上图对应的数值为: 要怎么解决呢?进行数据转换就行,这里可以封装方法,或者用第三方的
mediatemple - can#39;t send email using codeigniter(mediatemple - 无法使用 codeigniter 发送电子邮件)
Laravel Gmail Configuration Error(Laravel Gmail 配置错误)
Problem with using PHPMailer for SMTP(将 PHPMailer 用于 SMTP 的问题)
Issue on how to setup SMTP using PHPMailer in GoDaddy server(关于如何在 GoDaddy 服务器中使用 PHPMailer 设置 SMTP 的问题)