Я только что изменил все свои 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']; }
Это отлично работает на localhost, но у моего сервера веб-хостинга нет mysqlnd, поэтому get_result()
не работает. Установка mysqlnd не является вариантом.
Каков наилучший путь отсюда? Могу ли я создать функцию, которая заменяет get_result()
и как?
Вот более аккуратное решение, основанное на том же принципе:
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; } }