Как я могу поместить результаты подготовленного оператора MySQLi в ассоциативный массив?
-
13-09-2019 - |
Вопрос
У меня есть запрос 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?
Решение
Попробуйте следующее:
$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()
функция для вас по каждому из этих параметров.
После этого остается просто просмотреть каждую строку, создать для каждой строки ассоциативный массив и добавить его в массив, в результате чего будут получены все результаты.
Другие советы
Обновлять: Начиная с PHP 5.3.0, вы можете получить объект mysqli_result, предоставляющий метод fetch_array.
$sql = 'SELECT photographers.photographer_id, photographers.photographer_name
FROM photographers';
$data = null;
$stmt = $conn->stmt_init();
if ($stmt->prepare($sql)) {
$stmt->bind_result($photographer_id, $photographer_name);
$OK = $stmt->execute();
$result = $stmt->get_result();
$data = $result->fetch_array();
}
Документация: http://php.net/manual/en/mysqli-stmt.get-result.php
Я наткнулся на это обсуждение, чтобы найти решение для получения данных из подготовленных операторов MySQLi без mysqlnd.Я разрабатываю класс для удобной обработки подготовленных операторов с помощью 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!
Как ни странно, вы не можете.Просто невозможно получить объект mysqli_result из экземпляра mysqli_stmt.Я всегда считал это серьезным недостатком и предполагаю, что это одна из основных причин того, что mysqli так и не достигла реальной популярности.В наши дни его в значительной степени заменил PDO, который делает все, что вы хотите, без каких-либо усилий.
Редактировать: Мой ответ означает только то, что вы не можете сделать это по умолчанию.Конечно, вы можете реализовать это самостоятельно, как предложил Крис.Тем не менее, я думаю, вам следует использовать PDO, если это вообще возможно.
Если вы не можете использовать расширение 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;
}
}
Я надеюсь, что это полезно
Простой способ, который на самом деле удивительно работает.Я знаю, что это процедурно, но все же:
$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);
https://stackoverflow.com/users/5849505/carl-gentleman
Его ответ - один из способов для предыдущих версий php, поскольку «call_user_method_array» УСТАРЕЛ в PHP 4.1.0 и УДАЛЕН в PHP 7.0.0.
Поэтому я считаю уместным опубликовать обновленный ответ, по крайней мере, для PHP7, поскольку недавно я обнаружил, что у меня нет собственного драйвера MYSQLND для расширения MYSQLI на новом хосте, на который я перешел.Ура!...
Примечание:Здесь есть 2 функции.Требуется последний.Это единственный способ, которым я знаю, все это работает.(РЕДАКТИРОВАНИЕ. Ответ не создает ассоциативный массив...Зафиксированный)
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;
}