Я имею дело со старым приложением PHP, и мне было поручено убедиться, что во всех областях используются подготовленные операторы. В настоящее время он использует sprintf для построения большей части запроса перед выполнением.
Ниже приведен пример кода текущей реализации:
$queryString = "SELECT count(user.uid) as count
FROM user
LEFT JOIN voucher
ON user.voucher_uid = voucher.uid
LEFT JOIN affiliation
ON voucher.uid = affiliation.voucher_uid
@affiliation
LEFT JOIN account
ON affiliation.account_uid = account.uid
WHERE affiliation.account_uid IN (@accounts)
@active
@search
@template
@onlyown
AND voucher.template NOT LIKE 'api_%'
AND user.role != 'superadmin'";
$sql = replace_tokens(
$queryString,
array(
'accounts' => implode(', ', array_fill(0, count($accounts), '?')),
'template' => $template,
'search' => $search,
'onlyown' => $onlyown,
'affiliation' => $affiliation,
'active' => $active
)
);
return array_get(self::queryFetchOne($sql, $accounts), 'count', 0);
replace_tokens
Функция заменяет переменные, объявленные с @, перед ними на sql. Вот пример того, как @search
Переменная построена.
if (is_string($search) && !empty($search)) {
$search = sprintf('AND (voucher.code LIKE "%%%s%%" OR user.email LIKE "%%%s%%" OR user.salutation LIKE "%%%s%%")', $search, $search, $search);
} else {
$search = '';
}
Теперь я хотел бы решить проблему поиска, изменив %%%s%%
в :search
и просто используя именованный параметр. Тем не менее $accounts
Переменная является массивом имен учетных записей и использует параметры вопросительного знака для оператора in.
Ответ на мои вопросы, вероятно, нет, но я хотел бы решить эту проблему, не используя только параметры вопросительного знака, что потребовало бы от меня отслеживания порядка, который я сохраняю для всех параметров при построении массива.
Есть ли хорошие способы привязать параметры к частичному утверждению или обойти проблему использования большого количества параметров вопросительного знака, которые я описал выше?
Я решаю эту проблему путем создания двух переменных: одна — строка запроса, а другая — хеш-массив параметров запроса.
if (is_string($search) && !empty($search)) {
$search = 'AND (voucher.code LIKE :code OR user.email LIKE :email OR user.salutation LIKE :salutation)';
$params['code'] = "%%$search%%";
$params['email'] = "%%$search%%";
$params['salutation'] = "%%$search%%";
} else {
$search = '';
}
К тому времени, как вы закончите со всем условным кодом, у вас будет хэш-массив параметров запроса, который вы можете передать в PDO execute()
,
Но вы должны убедиться, что все ваши именованные параметры являются уникальными. Если вы используете одни и те же имена в разных условных терминах поиска, наступит хаос. В этом случае позиционные параметры имеют преимущество.
Это ошибка инженерии.
Моя рекомендация; массив с переменными, который соответствует параметрам.
Например
Позволять $sql1 = "select * from Apples where a=? and b=?"
А также $sql2 = " or c=?;"
Оба сгенерированы из функций gen_sql1()
а также gen_sql2()
,
Просто иметь gen_sql1
вернуть первую половину массива: 1, 2
, Есть gen_sql2
Верните второй тайм: 3
,
В конце объедините массивы и получите массив и вставьте их в «?» параметры в соответствующем порядке:
$fullsql = "select * from Apples where a=1 and b=2 or c=3"