Не уже ли в mysqli нету нормального решения?
Нет.
Если делать канонически, то есть байндить все переменные через плейсхолдеры, то у нас наберется аккурат на экран кода!
Варианты сделать запрос без Prepared Statements и вместо них слепить из жувачки какие-то костыли, разумеется, АБСОЛЮТНО не годятся. Какой смысл было переходить на mysqli, если продолжать говнокодить в стиле mysql_* из прошлого века?
Поэтому я бы рекомендовал все же использовать Safemysql. Тем более, что количество кода сократится минимум в 5 раз - там, где mysqli нужно 5 строчек, на Safemysql нужна будет только одна. Ради одного этого стоило бы переписать.
Чтобы не быть голословным. Возьмём простейший пример получения одной переменной из запроса. Без циклов, с единственным фетчем.
raw mysqli:
$query = $mysqli->prepare('SELECT id FROM Publication WHERE cat=?');
$query->bind_param('s', $field_cat);
$query->execute();
$query->bind_result($id);
$query->fetch();
safemysql:
$id = $db->getCol('SELECT id FROM Publication WHERE cat=?s');
Как я и говорил - 5 к 1.
Если же нам нужно получить массив, то соотношение еще больше увеличивается, поскольку у mysqli код прибавляется, а у safemysql остается все так же одна строчка, только меняется вызываемый метод.
Update.
Кстати, есть вариант не переписывать весь код.
Safemysql можно подключить, используя существующее соединение mysqi, вот так:
$db = new SafeMySQL(['mysqli' => $mysqli]);
Таким образом, после соединения с mysql можно приинклюдить Safemysql, создать инстанс, и использовать его наряду с mysqli без каких бы то ни было лишних накладных расходов.
Таким образом искомый код сведется к
$ids = $db->getCol('SELECT id FROM Publication WHERE id IN (?a)', $field_cat);
(следует помнить, что для плейсхолдера ?a
нужно передавать массив, а не строку "1,2,4")
А в дальнейшем можно будет постепенно переписать и остальные запросы более оптимальным образом.