【问题标题】:Mysqli get_result alternativeMysqli get_result 替代方案
【发布时间】:2012-05-31 22:36:04
【问题描述】:

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

【问题讨论】:

    标签: php mysqli


    【解决方案1】:

    我遇到了同样的问题并使用答案中提供的代码解决了它 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();
      }
    

    【讨论】:

    • $var 的用途和用途是什么?而且.. $bindRet 用于哪里?为什么不使用 $stmt->bind_param()?
    • @danger89: $var 是插入到 SELECT 语句中的参数(注意 ?)。至于$bindRet:我写了“(为了清楚起见,大部分错误处理都被删除了)”。在我的“真实代码”中,我检查了!== FALSE 并采取相应措施。不直接使用bind_param 与保持引用完整有关。我不太确定那个,因为我已经很长时间没有使用它了。对不起。
    • @danger89 我更新了我的帖子以使示例用法更清晰。
    • 是否有可以作为精确替换的功能?例如,你有$result = getResult($stmt); 而不是$result = $stmt-&gt;get_result();,最后$result 是相同的。
    • 卢克我不这么认为,但请检查我的答案是否非常接近。
    【解决方案2】:

    这是基于与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
    }
    

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

    【讨论】:

    • 像魅力一样工作
    • 嗨 Felipe,我使用了这个代码,它可以正常工作 99%,但在某些情况下它失败了,在我的 db 表中有列包含此字符串“我们正在寻找使用过的石棉板。床单不应该被损坏。要求的厚度是 10 毫米。所以这个字符串失败了。有什么想法吗?
    • 列的名称和数据类型是什么?您有多确定问题出在此功能上?您是否排除了所有其他可能性?
    • 如何在没有 mysqlnd 的情况下获取 num 行?
    • 这太棒了,解决了一个大问题。我将我的代码上传到我的服务器,却发现我的服务器没有 mysqlnd,这段代码对我有很大帮助
    【解决方案3】:

    我发现mysqli_stmt::get_result 的 API 文档页面上的匿名建议 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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-05
      • 2010-09-10
      • 2012-12-05
      • 2013-11-22
      • 2020-11-23
      • 2013-08-07
      • 2015-09-11
      相关资源
      最近更新 更多