Сравнение с другими библиотеками

Часто задают вопрос «а чем ваша библиотека лучше библиотеки X и почему я должен её использовать?».

Моя библиотека лучше тем, что лично мне она удобнее. А удобнее мне она потому, что писал её я. И писал так, чтобы лично мне было удобно. Написав, я выложил её в открытый доступ в надежде, что кому-нибудь она тоже доставит удовольствие.

Если же лично вам более удобна библиотека X, то правильным решением с вашей стороны будет использовать именно её. И ответ на вторую часть вопроса «почему я должен её использовать» — нипачиму. Вы совершенно не обязаны её использовать, я её никому не навязываю и полностью осознаю то, что она далеко не идеал.

Если же вам нравится использовать goDB в целом, но не нравятся частности, вы всегда можете внести предложения на форуме.

Однако, раз уж просят сравнить с другими библиотеками, я попытаюсь это сделать.

goDB vs DBSimple

Наиболее часто просят сравнить с DbSimple от Дмитрия Котерова.

Я с уважением отношусь к господину Котерову, и не имею ничего против, что его библиотекой пользуются (и на порядок большее количество людей, чем моей). Но специфика данной главы подразумевает, что мне придётся писать чем DbSimple плоха и чем goDB лучше :) Так что начнём.

Начнём прямо с «основных возможностей» со страницы DbSimple:

Поддержка PHP 4 и 5

В 2010 году, когда ожидается официальный выход PHP6, поддержка PHP4 не считается особым достоинством.

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

А ещё приходится передавать объекты по ссылке, из-за чего уже при подключении библиотеки PHP5 выкидывает Deprecated: Assigning the return value of new by reference is deprecated.

Deprecated можно отключить в настройках php, но лично для меня это было бы основанием отказаться от использования библиотеки уже после попытки просто её подключить. Но, так как это просто моё ИМХО, продолжим.

Поддержка СУБД: MySQL, PostgreSQL и InterBase/FireBird

Об этом аспекте написано у меня в F.A.Q.

Это, наверное, главное потенциальное преимущество DbSimple в этом споре. Если вам нужен FireBird, то goDB пока вам не подойдёт.

А если нужен MySQL: подойдёт. А в версии 2.0 будет и FireBird и Postgre и SQLite.

Подключение

DbSimple для абстрагировния от формата параметров использует стандартную строку DSN (Data Source Name):


$DB = DbSimple_Generic::connect("mysql://Логин:Пароль@Хост/База");
			

goDB одним из возможных вариантов использует не менее стандартный формат для хранения конфигурации в PHP — ассоциативный массив:


$config = array(
	'host'     => 'localhost',
	'username' => 'test',
	...
);
$db = new goDB($config);
			

Что лучше, сугубо дело вкуса. Единственное, что хочу заметить: вариант с массивом позволяет абстрагироваться от типа базы ничуть не хуже. Например для SQLite:


$config = array(
	'filename' => 'db.sqlite',
	'mode'     => 0777,
);
			
Хранение объекта подключения

goDB позволяет хранить различные объекты доступа к базам в своём же пространстве имён.

DbSimple об этом не заботится.

Обработка ошибок

goDB использует для сигнализации об ошибке генерацию исключений. Достаточно разветвлённая иерархия исключений, позволяет их гибко обрабатывать. Моё ИМХО: это наиболее корректное поведение.

DbSimple не может использовать исключения по причине совместимости с PHP4. Поэтому там требуется устанавливать обработчики ошибок:


$DATABASE->setErrorHandler('databaseErrorHandler');

// Код обработчика ошибок SQL.
function databaseErrorHandler($message, $info)
{
    // Если использовалась @, ничего не делать.
    if (!error_reporting()) return;
    // Выводим подробную информацию об ошибке.
    echo "SQL Error: $message<br><pre>"; 
    print_r($info);
    echo "</pre>";
    exit();
}			
			

Такой подход по моему ИМХО не является наиболее корректным. Так же моему ИМХУ не нравится постоянное использование собак (@):


if (!@$DB->query('UPDATE tbl SET field=? WHERE id=1', $field)) {
	$DB->query('INSERT INTO tbl(id, field) VALUES(1, ?)', $field)
}			
			
Плейсхолдеры

Одна из важнейших возможностей обоих библиотек: формирование запроса на основании шаблона с плейсхолдерами и набора входных данных.

Плейсхолдеры имеют различные типы для различного формата входных данных. Формат плейсхолдеров отличается, но эти отличия на уровне вкусовых.

Но в goDB различных плейсхолдеров банально побольше.

Формат входных данных

В DbSimple входные данные (те, которые должны заменить плейсхолдеры), передаются отдельными аргументами метода:


$pattern = 'INSERT INTO ...';			
$db->query($pattern, $value1, $value2, ...);
			

В goDB одним аргументом в виде массива:


$pattern = 'INSERT INTO ...';			
$data    = array($value1, $value2, ...);
$db->query($pattern, $data);
			

В goDB и нельзя по-другому: у query() есть дополнительные параметры. Однако, по другому и не нужно, так как такой формат, хотя и требует лишний раз написать array, всё же во многих случаях удобнее и нагляднее. Например, можно собирать список данных по условиям.

Именованные плейсхолдеры

Ещё одна возможность, доступная только при передаче данных в виде одного массива: именованные плейсхолдеры.

Если у нас есть структура, содержащая данные, которые следует использовать в запросе, можно использовать её напрямую.


$user = array(
	'name'     => 'Имя',
	'surname'  => 'Фамилия',
	'nickname' => 'vasa_c',
);			
$pattern = 'SELECT * FROM `users` WHERE (`name`=?:name AND `nickname`=?:nickname) OR (`name`=?:name AND `surname`=?:surname)';
$result  = $db->query($pattern, $user, 'assoc');
$db->query($pattern, $data);
			

В DbSimple придётся формировать список входных данных:


$user = array(
	'name'     => 'Имя',
	'surname'  => 'Фамилия',
	'nickname' => 'vasa_c',
);			
$pattern = 'SELECT * FROM `users` WHERE (`name`=? AND `nickname`=?) OR (`name`=? AND `surname`=?)';
$result  = $db->select($pattern, $user['name'], $user['nickname'], $user['name'], $user['surname']);
			
prepare stament

Расширение php_mysqli имеет возможность делать prepare/execute. goDB, будучи обратно совместимой с mysqli, также имеет такую возможность.

Надо признаться реализация эта не совсем удобная и в ближайших версиях goDB ожидается надстройка и над prepare/execute.

DbSimple делает prepare прозрачно в query(). Это увеличивает производительность для запросов, вызывающихся в одном сценарии многократно, но несколько снижает для одноразовых.

Так как в обычном веб-сценарии одноразовые запросы преобладают, прозрачный prepare является возможностью дискуссионной.

Кроме того, как увидим ниже, DbSimple вообще не использует его для MySQL.

Макроподстановки

Чуть ли не целый шаблонизатор внедрённый в DbSimple :)

По словам Д.К: «Начав однажды пользоваться {}-макросами, через некоторое время перестаешь понимать, как же обходился без них раньше.».

Впрочем, в тех примерах, что приводятся, тоже самое можно реализовать и другими способами, не требующих реализации шаблонизатора внутри библиотеки для БД. О том, что будет лучше с точки зрения заявленной «читабельности кода» опять таки можно холиварить.

Префиксы таблиц

В обоих библиотеках есть возможность задать глобальный префикс, а потом включать его в имена таблиц. С точки зрения удобства, обе реализации примерно на одном уровне, то есть опять дело вкуса. Разве что, в goDB — два варианта для вставки таблицы.


$dbSimple->setIdentPrefix('prefix_');
$godb->setPrefix('prefix_');
...
$dbSimple->select('SELECT * FROM ?_users');
$godb->query('SELECT * FROM {users}');
$godb->query('SELECT * FROM ?t', array('users'));
			
Разбор результата

Обе библиотеки позволяют представлять результат в различных форматах.

В DbSimple для каждого формата используется отдельный метод (select(), selectCell) + внедрение, непосредственно в запрос ARRAY_KEY.

В goDB формат задаётся аргументом query().

Что из этих двух подходов удобнее, опять-таки, вопрос всё того же вкуса. Уровень сложности для программиста у них одинаковый.

Отложенные подключения

DbSimple не реализует отложенных подключений. То есть, если вы создаёте объект базы в начале сценария, подключение произойдёт, даже если за весь сценарий не будет послано ни одного запроса.

Так как php_mysqli также не реализует отложенных подключений, то в godb 1.x для объектов базы их реализовать также не представляется возможным. Однако, они доступны при использовании пространства имён:


$config = array(
	'host' => 'localhost',
	...
	'postmake' => true,
);
...
goDB::makeDB($config);
...
goDB::queryDB($pattern, $data); // подключение будет осуществлено только перед первым запросом.
...
$db = goDB::getDB(); // или при получении объекта базы
$db->query($pattern, $data);
			
php_mysql vs php_mysqli

goDB построена поверх php_mysqli, расширения заменившего устаревшее php_mysql.

Адаптер mysql в DbSimple же использует старое php_mysql. Здесь в погоне за совместимостью со старым ПО, может даже нарушиться совместимость с новым: php_mysql обычно не включена по умолчанию в новых версиях.

Помимо более медленной работы старое расширение не поддерживает многих новых возможностей. Среди них те же самые prepare/execute, то есть DbSimple не поддерживает их для MySQL даже прозрачно.

Кэширование, логирование, пагинация и т.п.

Полезные вещи, которые присутствуют в DbSimple и отсутствуют в goDB. В соответствии с этим при взгляде под одним углом goDB значительно проигрывает.

При взгляде с другого угла, goDB старается сконцентрироваться на решении своих задач, а не становиться кухонным камбайном. Все эти вещи (ИМХО, ИМХО) должны решаться на совершенно других уровнях абстракции. Для логирования, в goDB есть возможность, как получения запросов на свой интерфейс, так и их перехват (декорирование).

Что интересно Д.К. сам ругает в документации другие библиотеки за избыточность.

Объём

В качестве достоинства DbSimple приводится объём - 40 Кб для работы с MySQL, против 200 Кб у ADOdb.

Не вижу большой разницы для серверных сценариев, но раз пошла такая пьянка — размер goDB 1 файл и 22 Кб (с комментариями).

© Григорьев Олег aka vasa_c, 2006—2010