简单的PDO包装器

Bv2*_*202 15 php database pdo wrapper

我的Web应用程序目前已执行简单的查询:简单的CRUD操作,计数,...

几个月前,有人建议我为此编写一个简单的PDO包装器(以避免每次执行查询时都编写try/catch,prepare(),execute()等).显示了这个示例方法(我做了一些更改,所以我可以在我自己的项目中使用它):

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;
  }
Run Code Online (Sandbox Code Playgroud)

因为我需要执行更多操作(执行查询,检索1条记录,检索多条记录,计算结果),我为所有这些创建了一个方法:

  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;
  }
Run Code Online (Sandbox Code Playgroud)

如您所见,大多数代码都是相同的.每种方法只有2行代码不同:$ result的初始化(我总是希望返回一个值,即使查询失败)和获取.我可以只编写其中一个方法而不是使用4种方法,并传递一个带有动作类型的额外参数.这样,我可以使用一堆switch语句的if/else语句.但是,我认为代码可能会变得混乱.这是解决这个问题的好方法吗?如果没有,那会是一个很好的解决方案吗?

我遇到的第二个问题(这就是我现在正在研究这个类的原因)是我想在LIMIT SQL语句中使用预处理语句.但是,不可能这样做:

$res = $pdo->prepare("SELECT * FROM table LIMIT ?");
$res->execute(array($int));
Run Code Online (Sandbox Code Playgroud)

变量将由于某种原因被引用(因此查询将失败),如下所述:https://bugs.php.net/bug.php?id = 40740

该解决方案似乎使用bindValue()并使用int数据类型作为参数:http://www.php.net/manual/de/pdostatement.bindvalue.php

我可以重写方法来支持这个,但我还需要使用额外的参数.我不能再使用$db->execute($sql, $variable1, $variable2);了,因为我需要知道数据类型.

解决这个问题的最佳方法是什么?

谢谢

Mik*_*ike 33

如何用你可以链接的方法创建一个类(为了清楚起见,我已经删除了错误检查):

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

// 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();
Run Code Online (Sandbox Code Playgroud)

bind如果你愿意,你可以改变接受数组或关联数组的方法,但我发现这个语法非常清楚 - 它避免了构建数组.参数类型检查是可选的,PDO::PARAM_STR适用于大多数值,但在传递空值时要注意潜在的问题(请参阅文档中的注释PDOStatement->bindValue).

  • 非常好主意,但我使用`$ row = $ db->查询('SELECT col1,col2,col3 FROM mytable WHERE id>:id LIMIT:limit') - > bind(":id",2) - > bind(":limit",1) - > single();`很容易阅读 (2认同)