2011-07-18 58 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'佔位符地方 –