【问题标题】:How can I put the results of a MySQLi prepared statement into an associative array?如何将 MySQLi 准备好的语句的结果放入关联数组中?
【发布时间】:2010-11-02 21:40:17
【问题描述】:

我有一个 sql 查询和一个 mysqli 准备好的语句:

$sql = 'SELECT photographers.photographer_id, photographers.photographer_name
    FROM photographers';

$stmt = $conn->stmt_init(); 
if ($stmt->prepare($sql)) { 
    $stmt->bind_result($photographer_id, $photographer_name);  
    $OK = $stmt->execute(); 
    $stmt->fetch();
}

如何将结果存储在关联数组中,以便稍后循环并获取 sql 字符串返回的所有数据?

【问题讨论】:

    标签: php mysqli prepared-statement associative-array


    【解决方案1】:

    尝试以下方法:

    $meta = $statement->result_metadata(); 
    
    while ($field = $meta->fetch_field()) { 
        $params[] = &$row[$field->name]; 
    } 
    
    call_user_func_array(array($statement, 'bind_result'), $params);            
    while ($statement->fetch()) { 
        foreach($row as $key => $val) { 
            $c[$key] = $val; 
        } 
        $hits[] = $c; 
    } 
    $statement->close(); 
    

    首先,您获取查询元数据并从中获取您获取的所有字段(您可以手动执行此操作,但此代码适用于所有查询,而不是手动构建)。 call_user_func_array() 函数在每个参数上为您调用 mysqli_stmt::bind_result() 函数。

    之后,只需遍历每一行并为每一行创建一个关联数组,然后将其添加到数组中即可得到所有结果。

    【讨论】:

    • 这不是我的代码,我不记得我是从哪里找到的。谷歌无疑会提供答案
    • 很棒的编码。我不知道元数据函数
    • $params[] = &$row[$field->name]; 中的 $row 来自哪里?
    【解决方案2】:

    更新:自 PHP 5.3.0 起,您可以 get a mysqli_result 提供 fetch_array 方法的对象。

    $sql = 'SELECT photographers.photographer_id, photographers.photographer_name
        FROM photographers';
    
    $stmt = $conn->prepare($sql);
    $stmt->execute();
    $result = $stmt->get_result();
    $data = $result->fetch_array();
    

    【讨论】:

    • 请注意,正如文档所说,这仅在您安装并运行 MySQL 原生驱动程序时才有效,而您的安装可能没有。
    【解决方案3】:

    奇怪的是,你不能。根本没有办法从 mysqli_stmt 实例中获取 mysqli_result 对象。我一直认为这是一个重大缺陷,并且猜测这是 mysqli 从未真正流行的主要原因之一。这些天来,它几乎已被 PDO 取代,它可以毫不费力地做你想做的事。

    编辑:我的回答只意味着你不能默认这样做。当然,您可以像 Chris 建议的那样自己实现它。不过,如果可能的话,我认为您应该改用 PDO。

    【讨论】:

      【解决方案4】:

      如果您不能使用 PDO 扩展。或者您在使用准备好的语句构建数据库类时遇到问题。 如何用于插入更新、删除和插入:

          $db = new database();
          $db->query = "INSERT INTO blabla (name,date,number) VALUES(?,?,?)";
          $db->params = array($name,$date,$number);
          $db->type = 'ssi'; //s=string,i=integer
          if($db->insert())
              echo 'success';
      

      Fetch 的工作方式有点不同

          $array = array();
          $db = new database();
          $db->query = "SELECT * FROM blabla WHERE id=? and someother=?";
          $db->params = array($id,$other);
          $db->type = 'is';
          $r = $db->fetch(); 
          //$r[0]['id'] for row 1
          //$r[0]['name'] for row 1
          //$r[1] .... For row 2
          //$r[2] .... For row 3
          //etc...
      

      现在是数据库类

          class database {
      
              private $stmt;
              private $mysqli;
              private $query;
              private $params = array();
              private $type;
      
              public function __set($name, $value) {
                  switch ($name) {
                      case 'params':
                          $this->params = $value;
                          break;
                      case 'query':
                          $this->query = $value;
                          break;
                      case 'type':
                          $this->type = $value;
                          break;
                      default:
                          break;
                  }
              }
      
              public function __get($name) {
                  if ($name !== "mysqli" && $name !== "stmt")
                      return $this->$name;
              }
      
              public function __construct() {
                  $this->mysqli = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME, DB_PORT);
                  $this->stmt = $this->mysqli->stmt_init();
              }
      
              private function close_con($bool) {
                  if ($bool) {
                      $this->stmt->free_result();
                  }
                  $this->stmt->close();
                  $this->mysqli->close();
              }
      
              private function nofetch() {
                  $this->stmt->prepare($this->query);
                  $bind_names[] = $this->type;
                  for ($i = 0; $i < count($this->params); $i++) {
                      $bind_name = 'bind' . $i;
                      $$bind_name = $this->params[$i];
                      $bind_names[] = &$$bind_name;
                  }
                  call_user_func_array(array($this->stmt, "bind_param"), $bind_names);
      
                  if ($this->stmt->execute()) {
      
                      $this->close_con(false);
                      return true;
                  }
                  $this->close_con(false);
                  return false;
              }
      
              public function insert() {
                  if ($this->nofetch()) {
                      return true;
                  }
                  return false;
              }
      
              public function update() {
                  if ($this->nofetch()) {
                      return true;
                  }
                  return false;
              }
      
              public function delete() {
                  if ($this->nofetch()) {
                      return true;
                  }
                  return false;
              }
      
              public function fetch() {
                  $result_out = array();
                  $this->stmt->prepare($this->query);
                  $bind_names[] = $this->type;
                  if (count($this->params) > 0) {
                      for ($i = 0; $i < count($this->params); $i++) {
                          $bind_name = 'bind' . $i;
                          $$bind_name = $this->params[$i];
                          $bind_names[] = &$$bind_name;
                      }
                      call_user_func_array(array($this->stmt, "bind_param"), $bind_names);
                  }
                  if ($this->stmt->execute()) {
                      $result = $this->stmt->result_metadata();
                      $cols = $result->fetch_fields();
                      foreach ($cols as $col) {
      
                          $name = str_replace("-", "_", $col->name);
      
                          $$name = null;
                          if ($name == null)
                              $name = 'name';
                          $bindarray[$name] = &$$name;
                      }
      
                      call_user_func_array(array($this->stmt, 'bind_result'), $bindarray);
                      $this->stmt->store_result();
                      $copy = create_function('$a', 'return $a;');
                      while ($this->stmt->fetch()) {
                          $result_out[] = array_map($copy, $bindarray);
                      }
                  }
                  $this->close_con(true);
                  return $result_out;
              }
      
          }
      

      希望对你有帮助

      【讨论】:

        【解决方案5】:

        我遇到这个讨论是为了找到一种解决方案,可以在没有 mysqlnd 的情况下从 MySQLi 准备好的语句中获取数据。我一直在开发一个类,用于以方便的方式使用 MySQLi 处理准备好的语句。请看一下代码,或者简单地使用它(参见代码段末尾的使用示例)快速编写准备好的语句并获得其结果。

        class DbUtils {
        
            private $host;
            private $user;
            private $pass;
            private $database;
            private $connection;
        
            public function __construct($host, $user, $pass, $database) {
        
                $this->host = $host;
                $this->user = $user;
                $this->pass = $pass;
                $this->database = $database;
                $this->connection = new mysqli($host, $user, $pass, $database);
        
            }
        
            public function query(Array $params) {
        
                $args = array();
        
                // 0. Correct the input function parameters
                if (array_key_exists("query", $params)) {
                    $args["query"] = $params["query"];
                } else {
                    throw new Exception("Parameter not found: 'query'.");
                }
                if (array_key_exists("types", $params)) {
                    $args["types"] = $params["types"];
                } else {
                    $args["types"] = '';
                }
                if (array_key_exists("input", $params)) {
                    $args["input"] = $params["input"];
                } else {
                    $args["input"] = array();
                }
        
                // 1. Check the connection:
                if ($this->connection->connect_errno) {
                    echo "Connection to MySQL failed: [" . $this->connection->connect_errno . "]: " . $this->connection->connect_error . "<br/>";
                }
        
                // 2. Prepare the sentence:
                if (!($stmt = $this->connection->prepare($args["query"]))) {
                    echo "Prepared statement failed: [" . $stmt->errno  . "]: " . $stmt->error . "<br/>";
                }
        
                // 3. Bind the input parameters:
                if ( ( 0 != sizeof( $args["input"] ) ) && !(call_user_method_array("bind_param", $stmt, array_merge(array($args["types"]), $args["input"])))) {
                    echo "Binding parameters failed: [" . $stmt->errno . "]: " . $stmt->error . "<br/>";
                }
        
                // 4. Execute the sentence
                if (!($stmt->execute())) {
                    echo "Sentence execution failed: [" . $stmt->errno . "]: " . $stmt->error . "<br/>";
                }
        
                // 5. Bind the results:
                $data = array();
                $meta = $stmt->result_metadata();
                $row = array();
                while( $field = $meta->fetch_field() ) {
                    $argos[] = &$row[$field->name];
                }
                call_user_method_array('bind_result', $stmt, $argos);
        
                // 6. Collect the results:
                while ($stmt->fetch()) {
                    foreach($argos as $key => $val) { 
                        $dataItem[$key] = $val; 
                    } 
                    $data[] = $dataItem;
                }
        
                // 7. Close the sentence:
                $stmt->close();
        
                // 8. Return interesting data properly ordered:
                return $data;
            }
        
        }
        
        // 1. Instantiate it:
        $dbUtils = new DbUtils(
            "127.0.0.1", 
            "user", 
            "password", 
            "database"
        );
        
        // 2. Query prepared statements like this:
        $users = $dbUtils->query(array(
            "query" => "SELECT * FROM user WHERE name LIKE ? AND pass LIKE ?;",
            "input" => array('%', '%'),
            "types" => 'ss'
        ));
        
        // 3. Enjoy securely CRUD Ops!
        

        【讨论】:

        • 投了赞成票,因为尽管“call_user_method_array”已贬值,但我仍然能够将它用于我非常需要的用途。我将在一分钟内发布工作的 php7 脚本。
        【解决方案6】:

        一个简单的,实际上令人惊讶的工作。我知道这是程序性的,但仍然:

        $query = "SELECT * FROM foo WHERE bar = ?;";
        
        $stmt = mysqli_prepare($dbc, $query);
        
        mysqli_stmt_bind_param($stmt, "s", $bar);
        
        mysqli_stmt_execute($stmt);
        
        $result = mysqli_stmt_get_result($stmt);
        
        return mysqli_fetch_assoc($result);
        

        【讨论】:

          【解决方案7】:

          https://stackoverflow.com/users/5849505/carl-gentleman

          他的回答是以前版本 php 的一种方式,因为“call_user_method_array”在 PHP 4.1.0 中已弃用,在 PHP 7.0.0 中已删除。

          所以我发现发布更新的答案是相关的,至少对于 PHP7,因为我最近发现自己在我转移到的新主机上没有用于 MYSQLI 扩展的 MYSQLND 本机驱动程序。耶!...

          注意:这里有两个函数。最后一个是必需的。这是我知道这一切的唯一方法。 (编辑答案不会产生关联数组...已修复)

              public function arr($query, $data, $format) { // Some parts have been used from others. I don't know who.
                                                  $d = array();
                                                  $row = array();
                      // 1. Connect to the database // This is how I do it
                                                  $db = $this->con;
                      // 2. Prepare the sentence:
                      if( !($stmt = $db->prepare($query)) ) { 
                                                  echo "Prepared statement failed: [" . $stmt->errno  . "]: " . $stmt->error . "<br>";
                                                  $d[0] = false;// I return an object array so [0] I can check later. It is true or false however I define it.
                                                  return $d; 
                      }
          
                                                  // cast to array
                                                  $data = (array) $data; 
                                                  $format = (array) $format; 
          
                                                  //Normalize format
                                                  $format = implode('', $format); 
                                                  $format = str_replace('%', '', $format);
          
                                                  // Prepend $format onto $values
                                                  array_unshift($data, $format);
          
                      // 3. Bind the input parameters: (note "call_user_func_array" is not depriciated)
                      if ( !(call_user_func_array( array( $stmt, 'bind_param'), $this->ref_values($data) )) ) {
                                                  echo "Binding parameters failed: [" . $stmt->errno . "]: " . $stmt->error . ";<br>";
                      }
          
                      // 4. Execute the sentence
                      if ( !($stmt->execute()) ) {
                                                  echo "Sentence execution failed: [" . $stmt->errno . "]: " . $stmt->error . ";<br>";
                      }
          
                      // 5. Prepare to Bind the results:
                                                  $meta = $stmt->result_metadata();
                      while( $field = $meta->fetch_field() ) {
                                                  $argos[] = &$row[$field->name];
                                                  $fld_nms[] = $field->name;
                      }
          
                      // 6. Bind the results to the argos array:
                                                  call_user_func_array( array( $stmt, 'bind_result'), $argos);
          
                                                  /* // I left some debuging tools that are helpful
                                                  echo "<br>argos<br>";
                                                  print_r($argos);
                                                  echo "<br><br>";
          
                                                  $class_methods = get_class_methods($stmt);
          
                      foreach ($class_methods as $method_name) {
                          echo "$method_name<br>";
                      }
                                                  */
          
                      // 7. Collect the results:
                      while ($ftch = $stmt->fetch()) {
                                                  $dataItem = array();
                                                  /*
                                                  echo "<br>ftch<br>";
                                                  print_r($ftch);
                                                  echo "<br><br>";
                                                  */
                          foreach($argos as $key => $val) { 
          
                                                  echo "Args: k:" . $key . "; v:" . $val . ";<br>";
                                                  $nme = $fld_nms[$key];
                                                  $dataItem[$nme] = $val; 
                                                  //$dataItem[$key] = $val; 
                          } 
                                                  $d[] = $dataItem; // I am not interested in returning the multi level array yet but I left it
                      }
          
                      // 8. Close the sentence:
                                                  $stmt->close();
          
                      // 9. Return interesting data properly ordered:
                                                  return $d;
          
              }
              private function ref_values($array) { 
                                                  $refs = array();
                  foreach ($array as $key => $value) {
                                                  $refs[$key] = &$array[$key]; 
                  }
                                                  return $refs; 
              }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-07-19
            • 2013-02-08
            • 1970-01-01
            • 2020-06-19
            • 1970-01-01
            • 1970-01-01
            • 2012-12-01
            • 1970-01-01
            相关资源
            最近更新 更多