Простая оболочка PDO - PullRequest
       9

Простая оболочка PDO

15 голосов
/ 19 июля 2011

Мое веб-приложение в настоящее время выполняет простые запросы: простые операции CRUD, подсчет, ...

Несколько месяцев назад кто-то рекомендовал мне написать для этого простую оболочку для 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;
  }

Как видите, большая часть кода одинакова.Только 2 строки кода различны для каждого метода: инициализация $ result (я всегда хочу вернуть значение, даже если запрос не выполняется) и выборка.Вместо того, чтобы использовать 4 метода, я мог бы написать только один из них и передать дополнительный параметр с типом действия.Таким образом, я мог бы использовать кучу операторов if / else оператора switch.Тем не менее, я думаю, что код может запутаться.Это хороший способ решения этой проблемы?Если нет, что было бы хорошим решением для этого?

Вторая проблема, с которой я столкнулся (именно поэтому я сейчас работаю над этим классом), заключается в том, что я хочу использовать подготовленные операторы с оператором LIMIT SQL,Однако это невозможно сделать:

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

По какой-то причине переменная будет заключена в кавычки (и поэтому запрос не будет выполнен), как объяснено здесь: https://bugs.php.net/bug.php?id=40740

Решение, кажется, использует bindValue () и использует тип данных int в качестве параметра: http://www.php.net/manual/de/pdostatement.bindvalue.php

Я мог бы переписать метод (ы) для поддержки этого, но мне также нужно было бы использовать дополнительный параметр.Я больше не могу просто использовать $db->execute($sql, $variable1, $variable2);, так как мне нужно знать тип данных.

Какой лучший способ решить эту проблему?

Спасибо

1 Ответ

33 голосов
/ 19 июля 2011

Как насчет создания класса с методами, которые вы можете объединить (для ясности я удалил проверку ошибок):

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 работает для большинства значений, но следует учитывать потенциальные проблемы при передаче нулевых значений (см. комментарий в документации PDOStatement->bindValue).

...