2012-05-25 22 views
11

我剛剛使用mysqli將所有的sql查詢改爲準備語句。爲了加速這個過程,我創建了一個函數(稱爲performQuery),它取代了mysql_query。它接受查詢,綁定(如「sdss」)和變量傳入,然後執行所有準備好的語句。這意味着改變我所有的舊代碼很容易。我的函數使用mysqli get_result()返回一個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']; 
} 

這工作在本地主機上很好,但我的虛擬主機服務器沒有可用的mysqlnd,因此get_result()不工作。安裝mysqlnd不是一個選項。

什麼是離開這裏最好的方式?我可以創建一個替代get_result()的函數,以及如何?

回答

24

這是基於同樣的原理了一個更簡潔的解決方案:

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 
} 

所以用法和語法幾乎是相同的。主要區別在於替換函數返回結果數組而不是結果對象。

+4

作品像一個魅力<3 –

+0

嗨菲利普,我用這個代碼,它很好的99%,但對於某些情況下它失敗,在我的數據庫表中有列包含此字符串「我們正在尋找使用石棉表。被破壞,所需厚度爲10毫米。「所以它失敗了這個字符串。任何想法? – Sandeep

+0

列的名稱和數據類型是什麼?你有多確定問題出在這個功能上?你排除了其他所有可能嗎? – Sophivorus

7

我遇到了同樣的問題,使用的 What's wrong with 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(); 
    } 
+0

$ var用於什麼地方和什麼? And .. $ bindRet用於哪裏?爲什麼不使用$ stmt-> bind_param()? – danger89

+0

@ danger89:'$ var'是插入到SELECT語句中的參數(注意'?')。至於'$ bindRet':我寫了「(爲了清楚起見,大部分錯誤處理都被刪除了)」。在我的「真實代碼」中,我檢查它是否爲「!== FALSE」,並據此採取行動。不直接使用'bind_param'與保持引用完好無損。我並不確定這一點,因爲我很久沒有使用過它了。對不起。 –

+0

@ danger89我更新了我的帖子,使示例使用更清晰。 –

0

我在API文檔頁面找到了mysqli_stmt::get_result的匿名建議posted as a note非常有用(我想不出比eval技巧更好的方法),因爲我們經常想對結果使用fetch_array()。然而,因爲我想迎合一個通用的數據庫對象,我發現它是一個問題,假設數值數組的代碼對所有的調用都是正確的,並且我需要專門爲所有使用assoc數組的調用者提供服務。我想出了這個:

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