@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));
  • Вопрос задан
  • 753 просмотра
Решения вопроса 4
usdglander
@usdglander Куратор тега PHP
Yipee-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);
  }
}
Ответ написан
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы