Как стать автором
Обновить

Комментарии 21

НЛО прилетело и опубликовало эту надпись здесь
Для начала не плохо :)
Но…
  • Форматирование. Это важный аспект, который поможет лучше понимать код, и легче с ним работать. Отступы на уровне class, use и т.д — не нужны. закрывающий ?> не рекомендуется. Посмотрите PSR-12
  • Есть такая замечателная библиоетка\приложение- composer. Позволяет легко настроить авто загрузку классов (и не только), что бы не писать постоянно required ..., в общим рекомендую к ознакомлению
  • тот параметр в подготовленных запросах называется placeholder
  • Для общего развития, $stmt->execute(); принимает первым аргументом как раз массив параметров, т.е можно было бы просто сделать
    $stmt->execute( [":key" => "value"]);
  • для дальнейшего обучения рекомендую добавить еще insert, delete, update методы
Для начала не плохо :)

Главное класс называется DB, а не BD. Это хороший знак :)
PSR-12 глянул. Огромное спасибо, в будущем исправлюсь. Про composer знаю и умею использовать ( по крайней мере на уровне автозагрузки), решил не использовать, потому что класс в отрыве от приложения, но понял что зря.

В моём проекте загрузка конфигов происходит вообще через отдельный класс.

За информацию про execute так же большое спасибо.

Планирую переписать статью, учту ваши замечания, ещё раз спасибо.

Ой, вот только insert, delete, update методов здесь не нужно. К обертке над ПДО они не имеют никакого отношения. Хочется сделать crud — делай отдельный класс, который будет использовать DB как сервис.
Но автору до этого ещё далеко, ему бы сначала с сырыми запросами попрактиковаться.

Я понимаю, если бы это было на Хабр Q&A c просьбой высказать мнения и замечания. Но что этот рассказ об ученической поделке делает в статьях Хабра?

Очередной сто тысяч первый велосипед очередного новичка. Вместо нормального построителя запроса — очередная ненужная обёртка, написанная только потому, что автору лень писать 3 строки кода на один параметризованный запрос. Впрочем, автор слишком плохо знает PDO и потому не в курсе, что строк кода надо всего 3 (но об этом ниже).

$dbinfo = require 'path/to/dbinfo.php';
Очевидное непонимание того, как надо писать код. Класс работы с БД вообще не должен знать, откуда берутся параметры подключения. Более того, каждый экземпляр нормально реализованного класса DB может подключаться к своей базе данных, что в данном случае вообще не предусмотрено.

Конструктор класса DB должен получать настройки подключения извне — в качестве своих параметров. И должен иметь возможность подключаться не только к MySQL.

Ещё две очевидные ошибки в конструкторе: отсутствие флага PDO::ERRMODE_EXCEPTION в параметрах подключения и отсутствие установки кодировки подключения (что для MySQL более чем актуально).

if ( !empty($params) ) {
	foreach ($params as $key => $value) {
		$stmt->bindValue(":$key", $value);
	}
}
$stmt->execute();
Совершенно лишний блок кода, заменяемый на
$stmt->execute($params);
Особенно порадовал бессмысленный if.

return $this->query("SELECT * FROM $table" . $sql, $params);
Данный код сработает только для имени таблицы, являющейся корректным идентификатором. Но что будет, если таблица БД называется, например, "*45/13" (допустимое в MySQL имя таблицы)?
И должен иметь возможность подключаться не только к MySQL.

Ну или хотя бы к нестандартному порту...

Спасибо за комментарий, исправлюсь.
У незнающего человека возникает вопрос: «Что за двоеточие?» Я тут же отвечаю — такие запросы называются подготовленными и используются, дабы исключить возможность SQL инъекции.

Нет, выше уже сказали что это placeholder. Так же добавлю, что подготовленные запросы используются для ускорения их исполнения за счёт разбора на стороне СуБД каждого запроса лишь один раз.

Для исключения возможности инъекций используется раздельная передача запроса и его параметров, что достигается как при использовании prepared statement так и без них.

Вызывает определенные сомнения отсутствие lazy connect.
Вызывает сомнения отсутствие итераторов, повсеместное fetchAll вредно.

PS: Хотелось бы сказать, что малое количество критики связано с высоким качеством кода, однако нет. Критики мало потому, что и кода тоже мало. Статья оборвалась так же неожиданно, как и началась.
1. ни одной обработки ошибок…
2. получение одного ряда через получение всех и возврат первого — это ппц… а если мне нужно их все перебрать, но без получения всех в массив разом?
НЛО прилетело и опубликовало эту надпись здесь
Метода класса мог бы сам это дописать. Тогда исключается вероятность что программист использующий библиотеку забудет это сделать. Кейс с возможным двойным LIMIT так же исключается за счёт того, что такой код не заработает.
НЛО прилетело и опубликовало эту надпись здесь

Очень хорошо что нет "ни одной обработки ошибок". Потому что ни одной здесь и не нужно.

Хорошая попытка вернуть нас на 15 лет назад) Но нет, спасибо
Плохо это или хорошо, но такие штуки часто встречаются как тест задания на разных собесах
По комментариям, я провалил собеседование

Ну, хорошо что ты хоть сам это понимаешь.
Как правильно выше сказали, уровень этого кода никак не тянет на то чтобы кого-то чему-то учить. Неадекватность оценки собственного уровня — это большая проблема. Почему-то некоторые новички совсем не считают себя новичками — а наоборот, только написав свой первый скрипт, сразу бегут учить других. Даже не попробовав показать свой код не новичкам, чтобы получить замечания. И даже не попробовав использовать в реальном проекте. Ну нельзя так: написать код и тут же бежать на Хабр, писать статью, которая "будет полезна новичкам". Вот из-за таких статей над РНР все и смеются, думая что это и есть обычный РНР код. Надо было хотя бы попробовать свой хелпер в реальном проекте.


Из ключевых проблем:


  • не задаётся режим выброса исключений, то есть ты никак не узнаешь, в чем проблема, если запрос не выполнится
  • не задается кодировка. А потом начнутся вопросы, "у меня кракозябры выводятся!"
  • также при подключении желательно отключать режим эмуляции. Иначе попытка использовать плейсхолдеры для LIMIT окончится печально.
  • приватная переменная, которая содержит инстанс ПДО. То есть обратиться к методам ПДО нельзя. При том что их функционал не продублирован в своем классе. Это делает его абсолютно нежизнеспособным. Я понимаю что транзакции для тебя это что-то вроде высшей математики, но как ты обойдешься без получения insert id?
  • класс не должен сам ничего инклюдить. а должен получать конфигурацию через параметр конструктора
  • универсальный метод для выполнения запросов тут же пытается что-то фетчить. А это ничего, что запросы бывают не только SELECT? И попытка сделать fetchAll() после UPDATE может вызвать ошибку? И как теперь получить affected rows?
  • жестоко урезана функциональность PDO. getOne(), getCol() — это всё есть в ПДО. Как и множество других вариантов получения результата, о которых ты даже не подумал, например пары ключ-значение. Метод query() должен возвращать стейтмент. Который уже потом можно использовать либо напрямую в коде, либо в методах-хелперах класса
  • методы, которые за тебя пишут два слова от SQL запроса — это просто глупость. Я понимаю что это стремление сократить код, но в данном случае это не то на чем следует экономить. Полный текст SQL запроса читается и воспринимается гораздо лучше чем какой-то огрызок. Не говоря уже о том, что не всегда надо выбирать *
  • про биндинг в цикле уже много раз написали. От себя добавлю, что плейсхолдеры бывают не только именованные, но и позиционные. Которые твой класс не поддерживает, из-за этого самого цикла.

Но я оговорюсь: хотя как пособие для новичков этот код никуда не годится, но как "мой первый ПДО враппер" он неплох. Сама идея метода query() очень правильная, она не всем приходит в голову. В целом класс сделан нормально, идеи в целом верные. Не хватает только опыта в программировании и хотя бы минимальной обкатки кода в реальном проекте. Очень хорошо что класс компактный, в нем нету кучи ненужного мусора, который обычно натаскивают в такой враппер.


Если что-то непонятно по пунктам выше — спрашивай. А вот новую статью писать не надо. Рановато ещё.

Спасибо за информацию. Новую статью я всё же напишу, но лишь тогда, когда действительно освою данный инструмент.

Этот класс я использовал в реальных проектах и он работал, но видимо проект не раскрывал всей сути работ с базами данных.

За комментарий ещё раз спасибо, буду учиться.

Хорошо, пиши. Но сначала покажи мне что получилось

Да, собеседование не пройдено.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации