By now, you've certainly grasped the idea of binding to multiple variables. However, do not believe the admonitions about not using "SELECT *" with bind_result(). You can keep your "SELECT *" statements... even on your server requiring you to use bind_result(), but it's a little complicated because you have to use PHP's call_user_func_array() as a way to pass an arbitrary (because of "SELECT *") number of parameters to bind_result(). Others before me have posted a handy function for doing this elsewhere in these forums. I include it here:
// 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);
}
Now, to use this, we do something like:
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;
}
Now, fetch_my_data() will return an array of associative-arrays... all set to encode to JSON or whatever.
It's kinda crafty what is going on, here. stmt_bind_assoc() constructs an empty associative array at the reference you pass to it ($bound_assoc). It uses result_metadata() and fetch_field() to get a list of the returned fields and (with that single statement in the while loop) creates an element in $bound_assoc
with that fieldname and appends a reference to it in the $fields array. The $fields array is then passed to mysqli_stmt_bind_result. The really slick part is that no actual values have been passed into $bound_assoc, yet. All of the fetching of the data from the query happens in fetch_my_data(), as you can see from the fact that stmt_bind_assoc()
is called before the while($stmt->fetch())
.
There is one catch, however: Because the statement has bound to the references in $bound_assoc, they are going to change with every $stmt->fetch()
. So, you need to make a deep copy of $row. If you don't, all of the rows in your $result array are going to contain the same thing: the last row returned in your SELECT. So, I'm using a little array_copy() function that I found with the 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;
}