Как использовать 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>";