2012-05-25 17 views
11

Właśnie zmieniłem wszystkie moje zapytania sql do przygotowanych instrukcji używając mysqli. Aby przyspieszyć ten proces, stworzyłem funkcję (o nazwie performQuery), która zastępuje mysql_query. Pobiera kwerendę, wiązania (jak "sdss") i zmienne, aby przekazać, to robi wszystkie rzeczy o uporządkowanej instrukcji. Oznaczało to, że zmiana mojego starego kodu była łatwa. Moja funkcja zwraca obiekt mysqli_result przy użyciu mysqli get_result().Mysqli get_result alternatywa

Oznaczało to mogę zmienić mój stary kod:

$query = "SELECT x FROM y WHERE z = $var"; 
$result = mysql_query($query); 
while ($row = mysql_fetch_assoc($result)){ 
    echo $row['x']; 
} 

do

$query = "SELECT x FROM y WHERE z = ?"; 
$result = performQuery($query,"s",$var); 
while ($row = mysql_fetch_assoc($result)){ 
    echo $row['x']; 
} 

To działa prawidłowo na localhost, ale serwer mój hosting nie ma mysqlnd dostępne, dlatego get_result() nie praca. Instalacja mysqlnd nie jest opcją.

Jaki jest najlepszy sposób, aby przejść stąd? Czy mogę utworzyć funkcję, która zastępuje get_result() i jak?

Odpowiedz

24

Oto rozwiązanie neater oparte na tej samej zasadzie:

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; 
} 

Z mysqlnd normalnie można zrobić:

$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 
} 

I bez 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 
} 

więc wykorzystanie i składnia są niemal identyczne. Główną różnicą jest to, że funkcja zamieniająca zwraca tablicę wyników, a nie obiekt wynikowy.

+4

Działa jak urok <3 –

+0

Witam Felipe, użyłem tego kodu, to wygląda dobrze 99%, ale dla niektórych warunków się nie powiedzie, W mojej tabeli db istnieje kolumna zawierająca ten ciąg "Szukamy używanych arkuszy azbestowych. Arkusze nie powinny być uszkodzone, wymagana grubość to 10 mm. " więc nie powiedzie się dla tego ciągu. dowolny pomysł? – Sandeep

+0

Jaka jest nazwa kolumny i jej typ danych? Na ile jesteś pewien, że problem dotyczy tej funkcji? Czy wykluczyłeś każdą inną możliwość? – Sophivorus

7

I napotkał ten sam problem i rozwiązać go za pomocą kodu podanego w odpowiedzi na What's wrong with mysqli::get_result?

Moja funkcja wygląda tak teraz (obsługa błędów odpędza się dla jasności):

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; 
    } 

Wykorzystanie jak to:

$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(); 
    } 
+0

Gdzie i do czego służy zmienna $ var? .. gdzie jest używany $ bindRet? Dlaczego nie skorzystać z $ stmt-> bind_param()? – danger89

+0

@ danger89: '$ var' to parametr wstawiony do instrukcji SELECT (zwróć uwagę na'? '). Jeśli chodzi o '$ bindRet': napisałem" (większość błędów została usunięta dla jasności) ". W moim "prawdziwym kodzie" sprawdzam to dla '! == FALSE' i postępuję zgodnie z tym. Nie używanie 'bind_param' bezpośrednio miało coś wspólnego z utrzymywaniem nietkniętych referencji. Nie jestem tego pewien, ponieważ nie używałem go od dłuższego czasu. Przepraszam. –

+0

@ danger89 Zaktualizowałem swój post, aby uczynić przykład użycia bardziej przejrzystym. –

0

Znalazłem anonimową poradę posted as a note na stronie dokumentacji API dla mysqli_stmt::get_result bardzo przydatne (nie mogłem wymyślić lepszego sposobu niż sztuczka eval), ponieważ bardzo często chcemy fetch_array() na naszym wyniku. Jednakże, ponieważ chciałem obsłużyć ogólny obiekt bazy danych, odkryłem, że jest to problem, który zakłada, że ​​kod zakłada tablicę numeryczną w porządku dla wszystkich wywołań funkcji i musiałem obsłużyć wszystkich wywołujących używających wyłącznie tablic assoc. Wpadłem na to:

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; 
    } 
}