Как использовать bind_result() вместо get_result() в php

Я работаю над проектом для универа и использую следующий код на testing server в get all devices из таблицы на основе user_id:

public function getAllDevices($user_id) {
    $stmt = $this->conn->prepare("SELECT * FROM devices WHERE  primary_owner_id = ?");
    $stmt->bind_param("i", $user_id);
    $stmt->execute();
    $devices = $stmt->get_result();
    $stmt->close();
    return $devices;
}

Это работало нормально на моем тестовом сервере, но возвращает эту ошибку при миграции на сервер проекта университета:

Call to undefined method mysqli_stmt::get_result()

Некоторый поиск в Google предлагает использовать bind_result() вместо get_result() но я понятия не имею, как это сделать all fields в таблице. Большинство примеров показывают только возвращение one field

Любая помощь приветствуется

5 ответов

Решение

Предполагая, что вы не можете использовать get_result() и вы хотите массив устройств, вы можете сделать:

public function getAllDevices($user_id) {
    $stmt = $this->conn->prepare("SELECT device_id, device_name, device_info FROM devices WHERE  primary_owner_id = ?");
    $stmt->bind_param("i", $user_id);
    $stmt->execute();
    $stmt->bind_result($id, $name, $info);
    $devices = array();

    while($stmt->fetch()) {
        $tmp = array();
        $tmp["id"] = $id;
        $tmp["name"] = $name;
        $tmp["info"] = $info;
        array_push($devices, $tmp);
    }
    $stmt->close();
    return $devices;
}

Это создает временный массив и сохраняет данные из каждой строки в нем, а затем помещает его в основной массив. Насколько я знаю, вы не можете использовать SELECT * в bind_result(), Вместо этого вам будет досадно набирать все поля, которые вы хотите после SELECT

К настоящему времени вы наверняка поняли идею связывания с несколькими переменными. Тем не менее, не верьте указаниям не использовать "SELECT *" с bind_result(). Вы можете хранить свои операторы "SELECT *"... даже на своем сервере, требуя от вас использовать bind_result(), но это немного сложно, потому что вы должны использовать PHP call_user_func_array() как способ передачи произвольного (из-за "SELECT" *") количество параметров для bind_result(). Другие до меня разместили удобную функцию для этого в других местах на этих форумах. Я включаю это здесь:

// Take a statement and bind its fields to an assoc array in PHP with the same fieldnames
function stmt_bind_assoc (&$stmt, &$bound_assoc) {
    $metadata = $stmt->result_metadata();
    $fields = array();
    $bound_assoc = array();

    $fields[] = $stmt;

    while($field = $metadata->fetch_field()) {
        $fields[] = &$bound_assoc[$field->name];
    }    
    call_user_func_array("mysqli_stmt_bind_result", $fields);
}

Теперь, чтобы использовать это, мы делаем что-то вроде:

function fetch_my_data() {
    $stmt = $conn->prepare("SELECT * FROM my_data_table");
    $stmt->execute();
    $result = array();
    stmt_bind_assoc($stmt, $row);
    while ($stmt->fetch()) {
         $result[] = array_copy($row);
    }
    return $result;
}

Теперь fetch_my_data() вернет массив ассоциативных массивов... все они настроены для кодирования в JSON или что-то еще.

Это немного хитро, что здесь происходит. stmt_bind_assoc() создает пустой ассоциативный массив по ссылке, которую вы ему передаете ($bound_assoc). Он использует result_metadata() и fetch_field() для получения списка возвращаемых полей и (с этим единственным оператором в цикле while) создает элемент в $bound_assoc с этим именем поля и добавляет ссылку на него в массиве $fields. Затем массив $fields передается в mysqli_stmt_bind_result. Действительно приятная часть в том, что в $ bound_assoc не было передано ни одного фактического значения. Вся выборка данных из запроса происходит в fetch_my_data(), как вы можете видеть из того факта, что stmt_bind_assoc() называется до while($stmt->fetch()),

Однако есть одна загвоздка: поскольку оператор связывается со ссылками в $ bound_assoc, они будут меняться с каждым $stmt->fetch(), Итак, вам нужно сделать глубокую копию $ row. Если вы этого не сделаете, все строки в вашем массиве $ result будут содержать одно и то же: последняя строка, возвращенная в вашем SELECT. Итак, я использую небольшую функцию array_copy(), которую я нашел в Google:

function array_copy( array $array ) {
    $result = array();
    foreach( $array as $key => $val ) {
        if( is_array( $val ) ) {
            $result[$key] = arrayCopy( $val );
        } elseif ( is_object( $val ) ) {
            $result[$key] = clone $val;
        } else {
            $result[$key] = $val;
        }
    }
    return $result;
}

Для того, чтобы использовать bind_result() Вы не можете использовать запросы, которые SELECT *,

вместо этого вы должны выбрать отдельные имена таблиц, а затем связать результаты в том же порядке. вот пример:

$stmt = $mysqli->prepare("SELECT foo, bar, what, why FROM table_name WHERE id = ?");
$stmt->bind_param("i", $id);
if($stmt->execute()) {
    $stmt->bind_result($foo, $bar, $what, $why);
    if($stmt->fetch()) {
        $stmt->close();
    }else{
        //error binding result(no rows??)
    }
}else{
    //error with query
}

Ваш вопрос предполагает, что на вашем локальном сервере установлен собственный драйвер MySQL (MySQLnd), но на сервере школьных проектов MySQLnd отсутствует. Так как get_result() требует MySQL и.

Поэтому, если вы все еще хотите использовать get_result() вместо bind_result() на сервере школьного проекта, тогда вы должны установить MySQLnd на сервере школьного проекта.

get_result() теперь доступен только в PHP, установив собственный драйвер MySQL (mysqlnd). В некоторых средах может быть невозможно или нежелательно установить mysqlnd.

Несмотря на это, вы все равно можете использовать mysqli для выполнения запросов 'select *' и получать результаты с именами полей - хотя это немного сложнее, чем с помощью get_result()и включает в себя использование PHP call_user_func_array() функция. Ниже приведен пример, который выполняет простой запрос 'select *' и выводит результаты (с именами столбцов) в таблицу HTML:

$maxaccountid=100;
$sql="select * from accounts where account_id<?";
$stmt = $mysqli->prepare($sql);      
$stmt->bind_param('i', $maxaccountid); 
$stmt->execute();
print "<table border=1>";
print "<thead><tr>";   
$i=0;
$meta = $stmt->result_metadata();
$query_data=array();  
while ($field = $meta->fetch_field()) { 
  print "<th>" . $field->name . "</th>";
  $var = $i;
  $$var = null; 
  $query_data[$var] = &$$var; 
  $i++;    
}
print "</tr></thead>";
$r=0;
call_user_func_array(array($stmt,'bind_result'), $query_data); 
while ($stmt->fetch()) {                   
  print "<tr>";
  for ($i=0; $i<count($query_data); $i++) { 
    print "<td>" .  $query_data[$i] . "</td>"; 
  }
  print "</tr>";
  $r++;        
}
print "</table>";
$stmt->close();
print $r . " Records<BR>";
Другие вопросы по тегам