Mysqli get_result альтернатива
Я только что изменил все свои sql запросы на подготовленные операторы, используя mysqli. Чтобы ускорить этот процесс, я создал функцию (называемую performQuery
) который заменяет mysql_query
, Он принимает запрос, привязки (например, "sdss") и переменные для передачи, тогда он выполняет все выполненные операторы. Это означало, что изменить весь мой старый код было легко. Моя функция возвращает mysqli_result
объект с использованием mysqli get_result()
,
Это означало, что я мог изменить свой старый код с:
$query = "SELECT x FROM y WHERE z = $var";
$result = mysql_query($query);
while ($row = mysql_fetch_assoc($result)){
echo $row['x'];
}
в
$query = "SELECT x FROM y WHERE z = ?";
$result = performQuery($query,"s",$var);
while ($row = mysql_fetch_assoc($result)){
echo $row['x'];
}
Это прекрасно работает на локальном хосте, но мой сервер веб-хостинга не имеет MySQL, поэтому get_result()
не работает. Установка mysqlnd не вариант.
Какой самый лучший путь отсюда? Могу ли я создать функцию, которая заменяет get_result()
, и как?
3 ответа
Вот более точное решение, основанное на том же принципе:
function get_result( $Statement ) {
$RESULT = array();
$Statement->store_result();
for ( $i = 0; $i < $Statement->num_rows; $i++ ) {
$Metadata = $Statement->result_metadata();
$PARAMS = array();
while ( $Field = $Metadata->fetch_field() ) {
$PARAMS[] = &$RESULT[ $i ][ $Field->name ];
}
call_user_func_array( array( $Statement, 'bind_result' ), $PARAMS );
$Statement->fetch();
}
return $RESULT;
}
С mysqlnd вы обычно делаете:
$Statement = $Database->prepare( 'SELECT x FROM y WHERE z = ?' );
$Statement->bind_param( 's', $z );
$Statement->execute();
$Result = $Statement->get_result();
while ( $DATA = $Result->fetch_array() ) {
// Do stuff with the data
}
И без mysqlnd:
$Statement = $Database->prepare( 'SELECT x FROM y WHERE z = ?' );
$Statement->bind_param( 's', $z );
$Statement->execute();
$RESULT = get_result( $Statement );
while ( $DATA = array_shift( $RESULT ) ) {
// Do stuff with the data
}
Таким образом, использование и синтаксис практически идентичны. Основное отличие состоит в том, что функция замены возвращает массив результатов, а не объект результата.
Я столкнулся с той же проблемой и решил ее, используя код, приведенный в ответе Что не так с mysqli::get_result?
Моя функция теперь выглядит так (обработка ошибок удалена для ясности):
function db_bind_array($stmt, &$row)
{
$md = $stmt->result_metadata();
$params = array();
while($field = $md->fetch_field()) {
$params[] = &$row[$field->name];
}
return call_user_func_array(array($stmt, 'bind_result'), $params);
}
function db_query($db, $query, $types, $params)
{
$ret = FALSE;
$stmt = $db->prepare($query);
call_user_func_array(array($stmt,'bind_param'),
array_merge(array($types), $params));
$stmt->execute();
$result = array();
if (db_bind_array($stmt, $result) !== FALSE) {
$ret = array($stmt, $result);
}
$stmt->close();
return $ret;
}
Использование как это:
$userId = $_GET['uid'];
$sql = 'SELECT name, mail FROM users WHERE user_id = ?';
if (($qryRes = db_query($db, $sql, 'd', array(&$userId))) !== FALSE) {
$stmt = $qryRes[0];
$row = $qryRes[1];
while ($stmt->fetch()) {
echo '<p>Name: '.$row['name'].'<br>'
.'Mail: '.$row['mail'].'</p>';
}
$stmt->close();
}
Я нашел анонимный совет, опубликованный в виде заметки на странице документации API для mysqli_stmt::get_result, очень полезным (я не мог придумать лучшего способа, чем трюк с eval), так как мы очень часто хотим использовать fetch_array() для нашего результата. Однако, поскольку я хотел обслуживать универсальный объект базы данных, я обнаружил проблему, заключающуюся в том, что код предполагал, что числовой массив подходит для всех узлов вызовов, и мне нужно было обслуживать всех вызывающих абонентов, используя исключительно массивы сопоставлений. Я придумал это:
class IImysqli_result {
public $stmt, $ncols;
}
class DBObject {
function iimysqli_get_result($stmt) {
$metadata = $stmt->result_metadata();
$ret = new IImysqli_result;
if (!$ret || !$metadata) return NULL; //the latter because this gets called whether we are adding/updating as well as returning
$ret->ncols = $metadata->field_count;
$ret->stmt = $stmt;
$metadata->free_result();
return $ret;
}
//this mimics mysqli_fetch_array by returning a new row each time until exhausted
function iimysqli_result_fetch_array(&$result) {
$stmt = $result->stmt;
$stmt->store_result();
$resultkeys = array();
$thisName = "";
for ( $i = 0; $i < $stmt->num_rows; $i++ ) {
$metadata = $stmt->result_metadata();
while ( $field = $metadata->fetch_field() ) {
$thisName = $field->name;
$resultkeys[] = $thisName;
}
}
$ret = array();
$code = "return mysqli_stmt_bind_result(\$result->stmt ";
for ($i=0; $i<$result->ncols; $i++) {
$ret[$i] = NULL;
$theValue = $resultkeys[$i];
$code .= ", \$ret['$theValue']";
}
$code .= ");";
if (!eval($code)) {
return NULL;
}
// This should advance the "$stmt" cursor.
if (!mysqli_stmt_fetch($result->stmt)) {
return NULL;
}
// Return the array we built.
return $ret;
}
}