Поскольку у меня скрипты на PHP все больше и больше начинают сворачиваться к одной задаче — выборке из базы данных и передаче этих данных клиентским Java-скриптам, я себе облегчил участь тем, что создал удобный (для меня, конечно) класс по работе с базами данных MySQL.
Сразу оговорюсь — встроенный класс mqsli достаточно удобен и функционален, но сталкиваясь день ото дня с одними и теми же вопросами было бы странно немного не облегчить свою участь.
Вашему вниманию предлагается класс exDBase, это по сути своей оболочка для класса mysqli. Сразу оговорюсь — я программист начинающий, и готов в комментариях или личных сообщениях получить массу критики за написанный код. Я не очень владею RegExp например, которые сильно бы упростили код, возможно есть и другие претензии. Но, тем не менее…
Вся библиотека содержится в одном файле — exdbase.php. Это файл содержит описание класса exDBase. Чтобы начать работать, нужно просто, скачав файл, прописать такую строчку:
require_once ('exdbase.php');
Для начала создадим экземпляр класса, это очень просто:
$DB = new exDBase (DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
if ($DB->error)
echo "Ошибка соединения: $DB->error";
В свойстве $DB->error всегда будет ошибка последней операции (если была ошибка), либо оно будет пустым.
Формат практически идентичен созданию экземпляра класса mysqli. Естественно, вместо указанных в примере констант нужно подставить реальные значения для хоста, имени пользователя, пароля и имени базы данных.
Теперь можно и поупражняться. Допустим у нас есть готовая база данных, и в ней есть таблица clients с полями:
ID — уникальный номер, автоинкремент
NAME — имя клиента
AGE — возраст клиента
AMOUNT — сумма покупок
BLOCKED — булева переменная, заблокирован клиент или активен
SETTINGS — личные параметры, мы их храним в формате JSON
Запрос в базу данных
Давайте получим все записи из таблицы 'clients'. Для этого существует метод fetchArray.
$res = $DB->fetchArray ('clients'); // получаем все записи в виде массива ассоциативных массивов
if ($res)
foreach ($res as $client)
echo print_r ($client, true); // выдаем все записи на экран
А если мы хотим получить только первую запись запроса? Для этого есть метод fetchFirst.
$res = $DB->fetchFirst ('clients'); // получаем первую запись в виде ассоциативного массива
if ($res)
echo print_r ($client, true); // выдаем первую запись на экран
Но, нам вряд ли понадобится получать все записи из таблицы, всегда есть условия отбора (поле WHERE в команде SELECT). Как нам поступить? Да очень просто. Это второй аргумент методов fetchArray или fetchFirst.
Допустим, что мы хотим выбрать всех клиентов с именем John. В нашем классе это можно сделать двумя способами.
Первый — просто задать условие строкой вида «NAME = 'John'»
$res = $DB->fetchArray ('clients', "NAME = 'John'");
Второй — задать условие массивом:
$res = $DB->fetchArray ('clients', array ("NAME" => "John"));
А если есть еще условия? Например, возраст должен равняться 30 лет? Легко:
$res = $DB->fetchArray ('clients', array ("NAME" = "John", "AGE" => 30));
Таким образом можно объединять несколько условий поиска. Но равенство… А если мы хотим найти всех клиентов с именем John, которые старше 25 лет? Тут на помощь приходят специальные префиксы:
$res = $DB->fetchArray ('clients', array ("NAME" = "John", ">=AGE" => 25));
Кроме ">=" вы можете использовать: ">", "<", "<=", "!=", "<>", "!=". Таким образом можно создавать запросы разной степени сложности и всегда получать нужные ответы.
Третий параметр методов выборки из базы данных — это поля таблицы. Их можно задать как строкой (например: «NAME, AGE»), так и массивом: array («NAME», «AGE»).
$res = $DB->fetchArray ('clients', array ("NAME" = "John", ">=AGE" => 25), array ("NAME", "AGE"));
Четвертый и последний параметр методов выборки fetchArray и fetchFirst это порядок сортировки. Он также задается либо строкой (типа: «ID ASC, NAME DESC») либо массивом array («ID» => «ASC», «NAME» => «DESC»).
$res = $DB->fetchArray ('clients', array ("NAME" = "John", ">=AGE" => 25), array ("NAME", "AGE"), array ("ID" => "ASC", "NAME" => "DESC"));
Ну, заканчивая с получением данных вы спросите — а как лимитировать выборку? Например, нужны только 10 первых записей?
Это делается методом setLimit(), вот так:
$DB->setLimit (10);
$res = $DB->fetchArray ('clients', "NAME = 'John'");
Метод setLimit() работает только на один запрос, после этого лимиты обнуляются.
Вставка новых данных
Для записи новых данных существует метод insert().
$id = $DB->insert ('clients', array ("NAME" => 'Peter', "AGE" => 27, "AMOUNT" => 1000.25));
Он возвращает значение первичного ключа автоинкремента (если такой задан в таблице). В нашем случае он вернет ID вставленной записи.
Обновление данных
Обновление данных осуществляется методом update().
$DB->update ('clients', array ("NAME" => 'Peter'), array ("AGE" => 30, "AMOUNT" => 2000.25));
Мы обновили все записи где имя (поле NAME) — это 'Peter'. Второй аргумент метода — это условие выбора, точно в таком же формате как WHERE для SELECT. Ну, а третий аргумент метода — это сами данные. Теперь у всех таких записей с именем 'Peter' возраст будет равен 30, а сумма — 2000.25.
Удаление данных
Если вы уже поняли логику работы библиотеки, то удаление дастся очень просто. Метод называется delete().
$DB->delete ('clients', array ("NAME" => 'Peter'); // удалить все записи с именем 'Peter'
$DB->delete ('clients', array (">AGE" => '20'); // удалить все записи с возрастом больше 20.
Вот такой вот первый краткий экскурс в библиотеку exDBase. Существует еще целый ряд других, более продвинутых функций, но об этом в другой раз.
Скачать файл можно по ссылке
(Выберите загрузить файл по ссылке как ...)
Всем хорошего кода!
Комментарии (60)
maximw
20.08.2018 17:34+1Велосипедостроение это хорошо для практики. Но почитайте про ActiveRecord, ORM, Query Builder. Реализаций этого добра много, есть из чего выбрать.
lemproix
20.08.2018 17:35Есть такая хорошая штука как (GitHub/Gitlab/Bitbucket/etc) и посмотрите пожалуйста ее, там всё это "добро" уже есть !
rraderio
20.08.2018 17:36Метод setLimit() работает только на один запрос, после этого лимиты обнуляются.
$DB->setLimit (10); // т.е. если кто-то добавит новый код, то все может поломаться и у запроса ниже уже не будет LIMIT? $res = $DB->fetchArray ('clients', "NAME = 'John'");
SDKiller
20.08.2018 18:03Кто-то еще качает файлы по ссылке?
Если уж хотите, чтобы люди ознакомились с вашим кодом, залейте на гитхаб
zenn
20.08.2018 20:33+6Зачем «это» пропустили из песочницы… Я все понимаю, у всех разный уровень знания языка, но это ведь явный пример того, как не следует делать в 2018ом году. Просьба — верните «это» обратно в песочницу.
Gesper
20.08.2018 23:03Честно говоря, уже в 2010м так делать было не принято. То, что в статье показано — это уровень 90х. Хотелось бы код увидеть, но, судя по всему, автор не очень понимает как работает сервер и скачать исходник его обертки нам не светит
stychos
20.08.2018 20:54-1Ну хотя бы подобие ActiveRecord есть, уже неплохо. Следующий шаг — поддержка разных СУБД и маппинг на объекты.
VolCh
20.08.2018 22:05ActiveRecord это и есть маппинг )
stychos
20.08.2018 22:07-1Я имел в виду CodeIgniter-style ActiveRecord, там, конечно, скорее QueryBuilder, но тогда это так называлось :-) Хотя не уверен, поддерживает ли код автора Chaining вызовов, кода-то нет.
zelenin
21.08.2018 12:39вы разные вещи смешиваете. QueryBuilder — это построитель запросов. К объектам отношения не имеет.
VolCh
22.08.2018 12:42Точнее к маппингу записей базы на объекты и обратно отношения не имеет, если говорить о SQL QueryBuilder. Реализуют его обычно всё-таки на объектах, а не функциях :)
zelenin
22.08.2018 12:50построитель запросов. В конце я получаю построенный запрос. Что я дальше с ним делаю, это уже ответственность следующего шага. Но в итоге это что-то должно быть трансляцией запроса например в sql с последующим запросом в базу данных. Пока в моем описании места объектам нет.
stychos
22.08.2018 22:17Вы тут какую-то демагогию развиваете. CodeIgniter ActiveRecord. Дохера занудами заумными все стали, а подумать о том, что конечному пользователю насрать, как оно там в деталях и отдельных частях называется — не судьба. А о том, что со временем и сами названия меняются — тем более.
zelenin
22.08.2018 22:35конечному пользователю насрать
я общаюсь в комментах it-сайта в топике, касающегося программирования, на темы с ним же, с программированием, связанные. Если вы "конечный пользователь", то пропускайте мимо глаз и ушей наши "демагогии".
stychos
22.08.2018 22:59А кто Вы, если не такой же типичный конечный пользователь фреймворков? Если не можете понять, что раньше понятия QueryBuilder и ActiveRecord отличались от нынешних и пеной у рта начинаете мне доказываете что я тут разные вещи смешиваю? А представляете? — некоторые помнят времена, когда в массах и mysql-биндингов в пхп не использовалось, и люди писали самодельные велосипеды на файлах.
Fesor
23.08.2018 10:26+1раньше понятия QueryBuilder и ActiveRecord отличались от нынешних
Нет, раньше query builder как подход и active record как паттерн были тем же чем они являются сегодня. Это как бы суть названий и терминов — если они часто меняются, и у них нет четкого определения — то надо придумать новый термин с четким определением и перестать юзать что-то что вводит в заблуждение людей.
Причина по которой под ActiveRecord понимают все что угодно произрастает из безграмотности людей и подмены понятий (когда "паттерн" какой-то или идею подменяют конкретной библиотекой).
и люди писали самодельные велосипеды на файлах.
в 70-х? да, было такое. только тогда небыло ни mysql ни php да и концеп SQL-я только только зараждался. И нет ничего плохого в хранении данных в файлах, просто это сегодня имеет смысл только если вам надо специализированное хранилище (и вряд-ли вы что-то такое будете на php писать, хотя можно).
Fesor
23.08.2018 10:31+1А о том, что со временем и сами названия меняются — тем более.
от того что вы юзаете code igniter термин query builder своего значения не поменял ни разу. Это штука которая позволяет вам строить запрос. причем за выполнение этого запроса или за работу с result set оно уже не отвечает.
Причем, для того что бы вы могли с result set работать вам нужна какая-то информация о запросе (интроспекция) и проще всего это сделать добавив свой строитель запросов который будет эту инфу предоставлять для других компонентов вроде мэпперов каких и т.д. Ну и что бы не писать что-то типа
$db->execute($query)
и т.д. можно скрестить это дело и с коннекшен менеджером.
Но это просто конкретное решение конкретной библиотеки и никакого отношения к терминологии все это не имеет.
Что до "конечного пользователя" — проблема штук типа CI ActiveRecord в том что это создает ограничения применимости решений. Иногда хочется и не через PDO поработать а через какой-то асинхронный драйвер на модных нынче свуле, и оказывается что 99% всех квери билдеров это подкопирку содранные друг к друга куски гуано которые так просто не реюзать.
VolCh
23.08.2018 13:54Авторы CodeIgniter назвали, судя по вашей ссылке, `CodeIgniter ActiveRecord` свою имплементацию паттерна QueryBuilder
Quber
21.08.2018 02:41Собственно в первом комментарии всё правильно написали. Я бы добавил еще composer и git.
peresada
21.08.2018 07:20Про бесполезную для сообщества работу уже написали, но раз уж Вы сами упомянули, что Вы начинающий программист, то позвольте небольшой Code Review:
Не пишите на PHP как на Python$res = $DB->fetchArray ('clients'); // получаем все записи в виде массива ассоциативных массивов if ($res) foreach ($res as $client) echo print_r ($client, true); // выдаем все записи на экран
peresada
21.08.2018 07:26Еще забыл
$res = $DB->fetchArray ('clients'); // получаем все записи в виде массива ассоциативных массивов echo print_r ($client, true); // выдаем все записи на экран
Вы правда считаете, что подобное комментирование полезно?
zzzmmtt
21.08.2018 09:17«event и error» а как же catch (\Exception $e)?
peresada
21.08.2018 09:24аналогично, всегда бешусь, когда IDE автодополняет catch с названием переменной $e и ленюсь это поправить
Free_ze
21.08.2018 11:29А вообще часто эвенты в catch приходят?)
zzzmmtt
21.08.2018 11:44Тут вопрос скорее в сокращении имен переменных, вместо $someError, $someEvent, $someException — везде могут написать $e, и разбирайся потом как хочешь.
Fesor
21.08.2018 11:48ну у вас еще тип есть, который неплохо дополняет какое-то общее
$error
или$event
. Опять же в этом случае нет смысла в суффиксах для типов (InvalidArgumentException
вместоInvalidArgument
).peresada
21.08.2018 12:50Понятное дело, что IDE и знание проекта всегда помогут, всегда подскажут. Но если говорить о PHP, это часто подразумевает fullstack разработку, то есть периодически нужно и на JS переключаться, и с базой уметь работать. Так вот из-за того, что люди привыкают сокращать такие вещи или дают однотипные имена, получается неразбериха в том же JS, типа
passwordInput.addEventListener('click', function(event) { var minClickAreaPercent = 0.8; // далее 80% от левого края срабатывает переключение var toggleIsAble = (event.offsetX / this.clientWidth > minClickAreaPercent); // какой-то код }
В котором семантически правильней назвать аргумент функции не event (и уж тем более не e), а например mouseClick или mouseClickEvent, но да, людям лень потратить на 1\2 секунды больше на набор текста. К счастью, подобного рода проблемы не распространяются на долгоживущие проекты с постоянной командой разработки.
Free_ze
21.08.2018 11:59Кмк, если есть проблемы с идентификацией аргумента catch, то проблема вовсе не в этом. Я неместный в PHP, но события (если речь о «наблюдателе») через исключения кажутся крайне сомнительным решением. А сам язык позволяет указывать тип исключения. В отличие от функций, у catch едва ли можно подчеркнуть какую-либо семантику, которую не сможет выразить тип.
zzzmmtt
21.08.2018 12:22У меня лично проблем с идентификацией исключений нет, но именовать так переменные — не самый лучший вариант. Никто не запрещает использовать $e для ошибок, ивентов или исключений, но $someEvent будет гораздо понятнее, чем $e. Изначально у автора $res — resource или result? Предполагаем, что таки result, но автор мог и до $r тогда сократить, а тут уже гораздо больше вариантов интерпретации имени переменной другими разработчиками (как минимум row можно ещё предположить).
Я и сам раньше грешил переменными типа $fido, $fids — мне понятно, что $fido — ресурс открытый fopen на чтение, fids — на запись, но потом сам начинаешь в этом путаться, переназначать случайно эти переменные.Free_ze
21.08.2018 13:19У меня лично проблем с идентификацией исключений нет, но именовать так переменные — не самый лучший вариант.
То есть обоснования нет, но вы склоняетесь к определенному варианту. Это нормально, вкусы у людей отличаются, но это не стоит замечания на код-ревью.
Тянуть сюда аналогию с локальными переменными или формальными параметрами функций — можно, но, имхо, это уже педантизм)zzzmmtt
21.08.2018 13:35Может быть и педантизм, но есть стандарты (PSR для php) и общепринятые практики, их было бы неплохо соблюдать, меньше придирок будет.
Free_ze
21.08.2018 13:52Ну вот PSR как раз рекомендует
$e
.
К любым гайдам и стандартам нужно подходить критически, не отключать мозг, включая линтеры и автоформатеры. Некоторым людям порой свойственно изображать педанта и часами спорить о малозначимой ерунде. Это точно хуже, чем просто плохой стиль)peresada
21.08.2018 14:07PSR — это принцип форматирования кода, а не принцип семантического именования. PSR ругнется на название класса с маленькой буквы, но ему без разницы если класс называется Ee. В приведенном примере говорится лишь об отступах, скобках и порядке
unnutz
21.08.2018 14:37Буду занудой, но PSR — это PHP Standard Recommendation. PSR-1 и PSR-2 действительно являются рекомендациями к форматированию и стилю кода, однако есть, к примеру, PSR-3, PSR-6 и PSR-7, которые описывают интерфейсы для логирования, кеширования и взаимодействия посредством HTTP-протокола соответственно.
VolCh
21.08.2018 16:14Но они по факту тоже не объясняют и, тем более, не диктуют принципы именования. Они дают жёстко заданные имена, которые нужно использовать в конкретных кейсах для совместимости, но не задают даже имён наследников.
Free_ze
21.08.2018 14:41Зачем же вы тогда сослались на него?) Ладно, предположим, что это недостаток конкретного документа (хотя судя по стайлгайдам других языков с нормальными примерами, никто еще не придумал внедрять семантику в имя переменной-исключения).
Хорошо, давайте исследовать «общепринятые практики» из живых проектов на PHP: YII, Composer, WordPress, Joomla и куча встреченных мной топ-проектов на GitHub (по звездам) используют "$e
" или что-то не менее «семантичное», вроде "ex
" или "err
". Выходит, это авторское изобретение.peresada
21.08.2018 14:54Я не ссылался на PSR. А проблема заключается имхо в другом:
Выходит очередная статья, документация, книга, любая авторская работа. Если она становится популярна, как с точки размера аудитории, так и с точки зрения вклада в сообщество, то многие принимают ее за чистую монету и считают, что абсолютно все в этому труде нужно брать за эталон => в том числе берут оттуда такую информацию, которую автор возможно и не планировал донести.
Это явно прослеживается и в примере с try catch из PSR. Суть этого правила заключается в отступах, порядке и скобках, а саму переменную исключения добавили потому что без нее пример казался бы некорректным. Разумеется ее нельзя выкидывать даже для примера, поэтому по привычке добавили $e.
Именно по привычке, потому что еще раньше эту несчастную $e опубликовали в какой-нибудь известной статье, а автор этой статьи еще раньше прочитал известную книгу, где автор повествовал об обработке исключений, но решил сэкономить на печатном пространстве и сократил $exception до $e, ведь в этой книге вообще не было целей говорить о семантике и правилах хорошего тона в коде.Free_ze
21.08.2018 15:13Да, я не обратил внимания на то, как вы внедрились)
Это достаточно очевидное сокращение в данной синтаксической конструкции, чтобы для него воскрешать венгерскую нотацию. Еще и стандарт де-факто. Допустимая вкусовщина, а не хороший тон, кмк.
zelenin
21.08.2018 14:50Ну вот PSR как раз рекомендует $e.
нет, он рекомендует расстановку пробелов и скобочек. То, что там написано $e, к стандарту не относится.
Lure_of_Chaos
21.08.2018 08:02+1Действительно, тема вечная: давно есть адекватные решения, но новички продолжают писать своих убийц pdo с sql injection и выборками в коде, но зато без *фатального недостатка*
MetaDone
21.08.2018 10:58Как всегда ссылка на кошерный сборщик запросов — https://github.com/auraphp/Aura.SqlQuery
Fesor
21.08.2018 11:37Большинство php-ных строителей запросов чуть-чуть лучше чем тупая конкатенация строк. Увы. Неужто людям больше от жизни не надо?
MetaDone
21.08.2018 11:50видать задачи где подойдет именно «строитель запросов чуть-чуть лучше чем тупая конкатенация строк» простые и сводятся к обычным выборкам максимум с парой условий. Или же людям, которые занимаются в основном такими задачами, лень потыкать существующие отлаженные инструменты и проще сделать очередной костыль тупо под задачу и использовать его
VolCh
21.08.2018 12:21Если именно строители запросов, то что там особо больше ждать? Другое дело, если используются высокоуровневые абстракции типа ORM, Repository и Criteria.
Fesor
21.08.2018 13:38Где-то месяца 3-4 назад я тоже так думал а потом начал загоняться по всяким там возможностям выводить типы, верифицировать запрос (даже по частям) на соответствие схеме без необходимости запуска оного, вопросы композиции запросов (открыл для себя парочку вариантов на тупой конкатенации которые интереснее и удобнее чем то что предлагает большинство билдеров, через под запросы естественно). Ну и т.д.
Что до абстракций типа ORM, репозиториев и критерий — все это прекрасно работает опять же в ситуации когда у тебя все выборки можно влипить в WHERE. без джойнов, подзапросов и прочих оконных функций. Чуть сложнее и абстракции эти перестают помогать (в том виде в котором они существуют в PHP) что опять же ставит вопрос «а нафига оно все надо!?» Ведь взять ту же доктрину (как бы я ее не любил) но на ее изучение нужно немало времени, в ней полно багов, это очень сложный продукт сам по себе… и тот факт что оно помогает мне только для очень простых задач меня очень расстраивает.
Stalker_RED
Такие штуки было модно писать в конце прошлого тысячелетия. Странно, что вы не нашли ни одной готовой, а написали свою.
Я просто оставлю это здесь:
php.net/manual/ru/pdo.prepared-statements.php
ru.wikipedia.org/wiki/ORM
zelenin
даже на хабре подобных статей было вагон и маленькая тележка.
kricha
так это для хабра или все-таки для облегчения собственной работы? Но сути не меняет, такое уже есть и даже более интуитивное, чем ваш вариант.
з.ы. сорри, показалось, что вы автор. пропускайте коммент.