2011-07-18 57 views
15

我的web应用程序目前已做执行简单的查询:简单的CRUD操作,计数,...简单PDO包装

几个月前,有人建议我在这里写这个简单的PDO包装(避免编写每次执行查询时都要尝试/ 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; 
    } 

,因为我需要执行更多的操作(执行查询,检索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; 
    } 

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

我有第二个问题(这就是为什么我现在正在处理这个类的原因)是我想用LIMIT SQL语句使用预处理语句。但是,这是不可能做到这一点:

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

的variabele将被引用出于某种原因(所以查询将失败),因为这里说明: https://bugs.php.net/bug.php?id=40740

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

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

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

感谢

回答

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

然后,您可以使用它像这样:

// 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适用于大多数值,但在传递空值时请注意潜在问题(请参阅comment in PDOStatement->bindValue文档)。

+1

这很漂亮,迈克。我喜欢可连续班的想法! – dotancohen

+2

非常好的想法,但我会使用'$ row = $ db-> query('SELECT col1,col2,col3 FROM mytable WHERE id>:id LIMIT:limit') - > bind(“:id”,2) - > bind(“:limit”,1) - > single();'很容易阅读 – Ergec

+1

@Ergec只是一个提示,即使两个参数的值都相同,也不能有两次相同的':limit'占位符地方 –