Взгляните на код PHP:
$user->v_useragent = 'coresky.agent';
Такой код может спровоцировать SQL запрос UPDATE или INSERT, а может и не спровоцировать если идентичные данные уже установлены в БД, собственно поэтому этот функционал именуется «Призрачные SQL запросы». Дело в том, что этот функционал, направлен на то что вначале работы скрипта, часто будет происходить чтение из ячейки БД, а потом возможна запись. Он имеет потенциал довольно широко применяться в веб-приложениях, особенно в тех, где не используется ORM, но я не видел чтобы он был где-то описан. ORM обычно имеют встроенные похожие алгоритмы. Давайте разберемся в деталях, что есть хорошо и что плохо в описываемом функционале.
В коде для повторного использования, для организации «призрачных запросов» необходимо иметь три метода, первый приведу полностью, так как он довольно прост:
class SKY // код из проекта coresky
{
...
static function &ghost($char, $original, $sql = '', $flag = 0) {
SKY::$mem[$char] = [$flag, $flag & 4 ? null : $original, $sql, []];
if ($sql)
trace('GHOST SQL: ' . (is_array($sql) ? end($sql) : $sql), false, 1);
if ($original) foreach (explode("n", unl($original)) as $v) {
list($k, $v) = explode(' ', $v, 2);
SKY::$mem[$char][3][$k] = unescape($v, true);
}
return SKY::$mem[$char][3];
}
Входные параметры метода:
- $char — одна маленькая буква английского алфавита, указывает на тип функционала призрачных запросов, может использоваться в префиксах переменных, как в примере выше;
- $original — текстовое содержимое ячейки БД (`mediumtext` для MySQL), где скопом хранятся все переменные призрачных запросов $char. На вход может подаваться и пустая строка;
- $sql — шаблон запроса, который будет использоваться для генерации реального SQL запроса, например в callback функции для register_shutdown_function();
- $flag — флаг. Чаще используется предустановленное значение 0;
Шаблоны запроса могут быть двух типов, на основе функций sql(..) или sqlf(..). Код второй приведу полностью, так как он, при правильном использовании, гарантирует невозможность SQL инъекций, он быстр и довольно прост:
function sqlf() { # quick parsing, using printf syntax. No SQL injection!
$in = func_get_args();
$tpl = array_shift($in);
if ($pos = strpos($tpl, '$'))
$tpl = preg_replace('/$_(w+)/', T_PREFIX . '$1', $tpl);
$sql = vsprintf($tpl, array_map(function ($a) {
if (!is_array($a))
return is_num($a) ? $a : escape($a); # just escape ALL parameters if not numeric
return implode(', ', array_map(function ($v) {
return is_num($v) ? $v : escape($v); # just escape ALL parameters if not numeric
}, $a));
}, $in));
return sql(1, $sql);
}
К сожалению, функция sqlf() не универсальна, с точки зрения составления произвольных SQL запросов в аспекте защиты от инъекций. Однако она существует параллельно с универсальной функцией sql(), из-за сравнительно высокой скорости работы. Шаблоны для sqlf() используются для случая работы только лишь с одной ячейкой mediumtext. Второй же шаблон, используется когда нужно организовать такие отложенные запросы для многих колонок таблицы.
Как происходит обработка, указанного кода PHP в самом начале статьи
Переменная $user содержит указатель на объект USER, который, в свою очередь, имеет магические методы __get() и __set(). По префиксу v_ класс понимает, что происходит запись в таблицу сессий `visitors` и вызыват метод SKY::save(..) который сохраняет код в массиве SKY::$mem. По окончанию работы скрипта, вызывается callback функция для register_shutdown_function(), в котором собственно осуществляется (или нет) реальный SQL запрос в БД.
Итак, остальные два метода, которые необходимы для организации функционала, это SKY::save(..) и SKY::here(..). Первый сохраняет данные в массив, а второй генерирует и выполняет реальный запрос в БД.
В коде coresky (повторно используемый код фреймворк или CMF) используется 8 типов призрачных SQL:
- системная конфигурация, которая хранится в БД;
- конфигурация посетителей;
- конфигурация авторизованных пользователей;
- системная конфигурация админки;
- системная конфигурация консольных запусков;
- три типа призрачных SQL используются для организации утилиты i18n;
Как видим «призрачные SQL» актуальны практически для всех web-приложений.
Достоинства описываемого функционала
- не нужно делать LATER TABLE… (или INSERT новых рядов) чтобы добавить новые переменные конфигураций, когда приложение развивается. Можно добавлять новые переменные просто в PHP коде, не изменяя структуру БД;
- функционал может сократить количество запросов к БД до одного, для случая когда происходит запись в один и тот-же ряд одной и той же таблицы;
Недостаток
Для переменных ghost SQL нельзя «прикрутить» индексы, скорее всего, нельзя сделать LOCK TABLE или использовать другие расширенные возможности MySQL.
Больше информации можно прочесть на сайте проекта SKY
Автор: coresky