13

我刚刚使用 mysqli 将所有 sql 查询更改为准备好的语句。为了加快这个过程,我创建了一个函数(称为performQuery)来替换mysql_query. 它接受查询、绑定(如“sdss”)和要传入的变量,然后执行所有 perpared 语句的内容。这意味着更改我所有的旧代码很容易。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(),如何创建?

4

3 回答 3

30

这是一个基于与lx answer相同原理的更简洁的解决方案:

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
}

所以用法和语法几乎相同。主要区别在于替换函数返回一个结果数组,而不是一个结果对象。

于 2015-05-30T21:17:55.937 回答
7

我遇到了同样的问题,并使用 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();
  }
于 2012-12-19T09:08:58.033 回答
0

我发现在mysqli_stmt::get_result的 API 文档页面上作为注释发布的匿名建议非常有用(我想不出比 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;
    }
}
于 2015-11-11T12:00:36.910 回答