Драйвер БД через PDO

Лучше делать драйвер через?


  • Всего проголосовало
    8

seyfer

Новичок
Решил сделать драйвер БД через PDO. С mydql напрямую все просто и однозначно, но не с PDO.
Возникло пару вопросов.

Драйвер должен состоять всего из 4-х ф-й : select, insert, update, delete. Логика их работы не имеет значения. Вызов просто $this->db->select(); в чем и профит.

У PDO есть ф-я query() которая просто для select и возвращает стейтмент, который можно потом fetch(). А что если в селекте есть параметры? Их же надо экранировать. Использовать sprintf() в связке с mysql_real_string когда речь идет о PDO не кошерно.

Сначала я написал ф-ю

Код:
public function Select($query) {
try {

            $stmt = M_PdoDB::query($query);

            $result_rows = array();
            while ($row = $stmt->fetch()) {
                $result_rows[] = $row;
            }

            return $result_rows;
        } catch (PDOException $e) {
            echo $e;

            return false;
        }
    }
И завис. Как же быть с параметрами? Для экранирования в PDO используется ф-я prepare(), куда передается sql запрос с параметрами WHERE например 'id = :id '. Далее делаем bindParam(':id', $my_id); и выполняем execute().
Хорошо, можно переписать мою ф-ю иначе:

Код:
public function Select($query, $param = array()) {

        try {

            $stmt = M_PdoDB::prepare($query);

            if ($param) {
                foreach ($param as $k => &$v) {
                    $stmt->bindParam(':' . $k, $v);
                }
            }
            $stmt->execute();
Но тогда надо помнить всегда про PDO, передавать sql в формате типа ':id' и параметры array( "id" => $id);
Есть ли какое-то более элегантное решение?

И что делать с запросами Insert и Update где я хочу узнать кол-во измененных столбцов? execute() возвращает true или false.
Можно использовать exec() но снова - как тогда быть с параметрами?
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
Не кошерно, это ты сам написал. Мало того, что нет такой функции, так еще и тебе PHP не даст смешать все в кучу.

У меня драйвер состоит их методов fetchAll, fetch, query.

Вызываю как $sql->query('SELECT * FROM Table WHERE id=:id', array(':id' => $id));
 

seyfer

Новичок
Не кошерно, это ты сам написал. Мало того, что нет такой функции, так еще и тебе PHP не даст смешать все в кучу.

У меня драйвер состоит их методов fetchAll, fetch, query.

Вызываю как $sql->query('SELECT * FROM Table WHERE id=:id', array(':id' => $id));
У меня сейчас так же работает select.
PHP:
// Запрос.
        $query = "SELECT * FROM pro_articles
            WHERE id_article = :id";

        $param = array(
            "id" => $id_article
        );

        if ($article = $this->DB->Select($query, $param)) {
            return $article;
        } else {
            return FALSE;
        }
Insert и Update похожим образом:

PHP:
public function Insert($table, $object) {

        $columns = array();
        $values = array();

        if ($object)
            try {
                foreach ($object as $key => $value) {
                    $columns[] = $key;

                    if ($value === null) {
                        $values[] = 'NULL';
                    } else {
                        $values[] = ":$key";
                    }
                }

                $columns_s = implode(',', $columns);
                $values_s = implode(',', $values);

                $query = "INSERT INTO $table ($columns_s) VALUES ($values_s)";
                $stmt = M_PdoDB::prepare($query);

                foreach ($object as $k => $v) {
                    $stmt->bindParam(":" . $k, $v);
                }

                if ($stmt->execute()) {

                    return true;
                } else {
                    $err = $stmt->errorInfo();
                    throw new PDOException($err[2]);
                }
            } catch (PDOException $e) {
                echo $e;

                return false;
            }
    }
Вопрос бы про то - можно ли как-то сделать лучше, чтобы абстрагироваться от вида :id например.
И самое насущное - возвращать кол-во измененных записей в Update и последний id в Insert. (конечно можно LASTID получать sql запросом).
Есть ли решения через PDO? Я не нашел в документации.
 

seyfer

Новичок
Мало того, что нет такой функции
Я и не ставил себе цели написать ф-ю полностью правильно, только передать смысл, и так ведь понятно. И я в курсе, что php не даст. Если я новичок на форуме, не значит, что в php.
 

seyfer

Новичок
theoretically safe - как-то не обнадеживает. prepare - execute обнадеживает больше.

На счет остальных вопросов Туплю...

string lastInsertId ([ string $name = NULL ] )

Нашел после того, как написал сообщение.

int rowCount ( void )

Есть у стейтмента, действительно.

Теперь есть все, что нужно. Тема закрыта.
 

ksnk

прохожий
prepare - execute обнадеживает больше.
Что-то мне подсказывает, что в prepare-execute используется тот-же quote, что и в PDO::quote. Просто чтобы не плодить сущностей сверх необходимого ;)
 

seyfer

Новичок
ответ на это вопрос - PDO::quote
К сведению на другом форуме пишут

Я уже пробовал, поверь мне на слово, что в случае prepare - execute без bind...() и фильтрования входящих данных инъекции проходят. Можешь поэкспериментировать.
Для селекта ("SELECT ... WHERE '$string' "):
$string = "whatever' OR 1+1; -- ";
Все, я - спать.

Через query вроде проходит.
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
Интересно, где такие запросы вообще существуют?)
 

Фанат

oncle terrible
Команда форума
Драйвер должен состоять всего из 4-х ф-й : select, insert, update, delete.
Фуфло редкостное. НИКОГДА не понимал, нафига городить отдельную функцию для DELETE. Та же фигня с инсёртом. Вот понадобился тебе INSERT IGNOIRE. И чо будешь делать?
Имхо, достаточно хелпер-функции, которая делает SET стейтмент из переданного массива.
Вызов просто $this->db->select(); в чем и профит.
Ну и где здесь профит?
Ну, то есть, да - мы економим унылый вайл (при том, что в ПДЕ есть, ваще-то, fetchALL).
Но а если нам нужен скаляр, а не массив?

не продумана структура методов совершенно. Такое ощущение, что класс пишется ради класса, а не для удобства

Как же быть с параметрами?
Элементарно.
Параметры передаем в метод вслед за кверей и суём в execute().

PHP:
public function Select($query) {
  $args = func_get_args();
  $query = array_shift($args);
 prepare($query);
 execute($args);
}
$data = $db->select("SELECT * FROM table WHERE id=?",$id);
И что делать с запросами Insert и Update где я хочу узнать кол-во измененных столбцов?
читать документацию?
 

seyfer

Новичок
Фанат, благодарю за критику.

4 ф-ии для начала. Дальше можно сделать так
PHP:
  public function insertMulti($table, $data){        
        foreach($data as $key=>$value){
            $this->insert($table, $value);
        }
    }
и так же
PHP:
     $sql = $this->query("SELECT * FROM `$table`");
        return $sql->fetchAll(PDO::FETCH_CLASS, "stdClass");
    
    }
Конечно можно и стандартным fetchAll, но я не вижу тут ограничений для повторного использования и расширения. Так что не фуфло. Тема была создана для решения других вопросах.

На счет параметров и вопросов с последним ИД я уже ответил выше. Разобрался.

Пример вот интересный, очень простой. Возьму на заметку.
 

Фанат

oncle terrible
Команда форума
ksnk твоё что-то право только наполовину. По умолчанию - да. Но умолчание это надо отключать, чтобы ПДЁ начало-таки использовать родные препареды.
 

Фанат

oncle terrible
Команда форума
Насчет параметров я уже ответил выше. Разобрался.
Передавать параметры массивом некошерно. Ну, то есть, если использовать именованные плейсхолдеры - то да.
но все равно ужасно занудно - столько лишних букв рисовать.

Я там подправил критику ещё.
 

seyfer

Новичок
Фанат, пример я так понял абстрактный, или рабочий? Что-то пропущены bindParam, может автоматом?..

И на счет аргументов - мне приятнее передавать в массиве, а в ф-ии делать foreach разбор. Может лишние действия, но нагляднее. хз
 

seyfer

Новичок
Фанат, не совсем понял вот это

Имхо, достаточно хелпер-функции, которая делает SET стейтмент из переданного массива.
С чем и как это едят? Как тогда инсерт делать?

А Делете это скорее для названия, чем функция.
 

seyfer

Новичок
Я вроде понял. В смысле формировать строку для sql из массива. Это и так делается у меня в Insert.

INSERT IGNOIRE - не понадобился пока. Тогда переделаю на хелпер функцию XD.
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
seyfer
Это не абстрактный пример, а пример, который ни одному мало мальски нормальному программисту не придет в голову.
 
Сверху