@phpcoder81

Хорошо ли написан класс БД?

Укажите пожалуйста на грубые ошибки в коде. Планирую использовать этот класс. Не хотелось бы потом внезапно наткнуться на проблемы. Ухожу с синглтона.
PS. всё началось с фразы "никакой работы с БД не должно быть в модели". Также начитался про SOLID)))
В общем верно ли написал код?

class DB
{
  protected $db;

  public function __construct(){
    //require_once 'config_db.php';
    try{
      $this->db = new PDO('mysql:host=localhost;dbname=test','root','');  
    }catch(PDOException $e){
      die('DB ERROR');
    }
  }

  private function query($query, array $params = array()){
    $stmt = $this->db->prepare($query);
    if(!empty($params)){
      foreach($params as $k => $v){
        if(is_int($v)){
          $stmt->bindValue(':'.$k, $v, PDO::PARAM_INT);
        }else{
          $stmt->bindValue(':'.$k, $v, PDO::PARAM_STR);
        }
      }
    }
    $stmt->execute();
    return $stmt;
  }

  public function getRows($query, array $params = array()){
    return $this->query($query, $params)->fetchAll(PDO::FETCH_ASSOC);
  }

  public function getColumn($query, array $params = array()){
    return $this->query($query, $params)->fetchColumn();
  }

  public function lastInsertId(){
    return $this->db->lastInsertId();
  }
}


class Car
{
  protected $db;

  public function __construct(DB $db){
    $this->db = $db;
  }

  public function getAll(){
    $query = "SELECT `id`, `name` FROM `cars`";
    return $this->db->getRows($query);
  }

  public function getById(int $id){
    $query = "SELECT `id`, `name` FROM `cars` WHERE `id` = :id";
    return $this->db->getRows($query, array('id' => $id));
  }
}



$db = new DB();

$car = new Car($db);

var_dump($car->getAll());

var_dump($car->getById(1));
  • Вопрос задан
  • 718 просмотров
Решения вопроса 4
usdglander
@usdglander Куратор тега PHP
Yippee ki-yay
die('DB ERROR');
Сразу нет! Класс не должен останавливать приложение, если произошла ошибка. Он должен бросать исключение, а что делать дальше должен решать клиентский код.

никакой работы с БД не должно быть в модели

В каком смысле это написано? Где это написано?

Ухожу с синглтона

На каждый запрос будете создавать отдельное подключение к БД? Там вообще то есть ограничение на количество открытых.

Я не заметил особой разницы между работой с mysqli и с вашим классом. Инкапсуляция бинда параметров метод query только? Так унаследуйтесь от класса mysqli и напишите удобный метод для этого.

И почему вы не берёте какую то готовую обёртку? Благо их написано тысячи!
Ответ написан
AleksandrB
@AleksandrB
Параметры бд обычно выносятся в отдельный файл.
Совсем забыл, die, exit внутри класса использовать нельзя.
Ответ написан
@FanatPHP
В целом подход правильный.
Именно с точки зрения SOLID и сам класс, и его использование спроектированы верно.

Можно поправить только по мелочам.

- код соединения никуда не годится. Брать отсюда: Как правильно соединяться с mysql в PDO
- при этом конфиграцию (хост, пароль, чарсет и прочее) вынести отдельно и передавать в конструктор в виде массива
- query() переписать так:
private function query($query, array $params = array()){
    $stmt = $this->db->prepare($query);
    $stmt->execute($params);
    return $stmt;
  }

- добавить getRow() и использовать в getById именно его.
- getRows переименовать в getAll чтобы не было путаницы и переписать так
public function getRows($query, array $params = array(), $mode= PDO::FETCH_ASSOC){
    return $this->query($query, $params)->fetchAll($mode);
  }
- либо добавить методы для всех методов PDO, либо сделать $db публичной. потому что когда тебе нужно будет выполнить десяток инсертов обернутых в транзакцию, эта обертка превратится в тыкву.
Ответ написан
php666
@php666
PHP-макака
1. Мое личное мнение - использовать PDO как движок для своей обертки - очень плохая идея. PDO универсален, тем самым он ограничивает многие возможности. По сути, это весьма усложненная и неторопливая махина.

2. Метод query до неприличия простой. Я не вижу тут никаких плюшек, нет ни одного преимущества обертки над самим PDO. Я писал много времени обертку над MySql, можешь посмотреть, что обычно добавляется к возможностям.

3. У обертки не должно быть методов типа getRows, getColumn и тп. отсебятины. Её функция - обрабатывать запросы, отдавать ответы и какие-то вспомогательные функции, типа lastInsertId и отдавать ошибки. Все остальное должно реализовываться в вышестоящем слое, неважно как ты его назовешь.

4.
всё началось с фразы "никакой работы с БД не должно быть в модели".
это правильно и это ты правильно понял, абстрагировав слой БД от слоя модели. Советую почитать книгу Фаулера "Архитектуру корп. пр. приложений" и особенно главу "Источники данных". Без этой концепции ты дальше своей подделки не уедешь в знаниях.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
profesor08
@profesor08
Чтоб получить имена столбцов и данные построчно, надо выполнить два одинаковых запроса. Спрашивается зачем? Можешь удалить весь код, и писать запросы станет легче.

Если же хочешь на классах, то тебе нужен один класс для создания запросов к бд, второй для обработки результата.

class Sql {
  public function query() {
    ....
    return new SqlResult($stmt);
  }
}

class SqlResult {
  public function __constructor($stmt) {
    $this->stmt = $stmt;
  }

  public function getCollumns() {
    return $this->stmt->fetchColumn();
  }

  public function getRows() {
    return $this->stmt->fetchAll(PDO::FETCH_ASSOC);
  }
}
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
Affor Москва
от 135 000 руб.
от 80 000 до 120 000 руб.
Zoon Москва
от 140 000 до 220 000 руб.
18 июл. 2019, в 11:59
20 руб./за проект
18 июл. 2019, в 11:57
13000 руб./за проект
18 июл. 2019, в 11:57
1500 руб./за проект