mysqli_stmt::bind_result

mysqli_stmt_bind_result

(PHP 5, PHP 7, PHP 8)

mysqli_stmt::bind_result -- mysqli_stmt_bind_result将变量绑定到准备好的语句以存储结果

说明

面向对象风格

public mysqli_stmt::bind_result(混合 &$var, 混合 &...$vars): 布尔型

过程式风格

mysqli_stmt_bind_result(mysqli_stmt $statement, 混合 &$var, 混合 &...$vars): 布尔型

将结果集中的列绑定到变量。

当调用 mysqli_stmt_fetch() 来获取数据时,MySQL 客户端/服务器协议将绑定列的数据放入指定的变量 var/vars 中。

可以在任何时间绑定或重新绑定列,即使结果集已部分检索。新的绑定将在下次调用 mysqli_stmt_fetch() 时生效。

注意:

在调用 mysqli_stmt_execute() 之后,以及在调用 mysqli_stmt_fetch() 之前,必须绑定所有列。

注意:

根据绑定变量的列类型,它们可能会静默更改为相应的 PHP 类型。

提示

此函数适用于简单的结果。要检索可迭代结果集,或将每一行作为数组或对象获取,请使用 mysqli_stmt_get_result()

参数

statement

仅过程式风格:由 mysqli_stmt_init() 返回的 mysqli_stmt 对象。

var

要绑定的第一个变量。

vars

要绑定的其他变量。

返回值

成功时返回 true,失败时返回 false

示例

示例 #1 面向对象风格

<?php

mysqli_report
(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");

/* 准备语句 */
$stmt = $mysqli->prepare("SELECT Code, Name FROM Country ORDER BY Name LIMIT 5");
$stmt->execute();

/* 将变量绑定到准备好的语句 */
$stmt->bind_result($col1, $col2);

/* 获取值 */
while ($stmt->fetch()) {
printf("%s %s\n", $col1, $col2);
}

示例 #2 过程式风格

<?php

mysqli_report
(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$link = mysqli_connect("localhost", "my_user", "my_password", "world");

/* 准备语句 */
$stmt = mysqli_prepare($link, "SELECT Code, Name FROM Country ORDER BY Name LIMIT 5");
mysqli_stmt_execute($stmt);

/* 将变量绑定到准备好的语句 */
mysqli_stmt_bind_result($stmt, $col1, $col2);

/* 获取值 */
while (mysqli_stmt_fetch($stmt)) {
printf("%s %s\n", $col1, $col2);
}

上面的示例将输出类似于以下内容

AFG Afghanistan
ALB Albania
DZA Algeria
ASM American Samoa
AND Andorra

参见

添加注释

用户贡献的注释 17 个注释

58
hamidhossain at gmail dot com
15 年前
很多人不喜欢 bind_result 如何与准备好的语句一起使用!它要求您传递很长的参数列表,这些参数将在函数被调用时加载列值。

为了解决这个问题,我使用了 call_user_func_array 函数和 result_metadata 函数。这使得操作变得容易,并自动返回一个数组,其中包含所有列结果,这些结果存储在一个带有列名的数组中。

请不要忘记将设置变量更改为自己的凭据

<?php
$host
= 'localhost';
$user = 'root';
$pass = '1234';
$data = 'test';

$mysqli = new mysqli($host, $user, $pass, $data);
/* 检查连接 */
if (mysqli_connect_errno()) {
printf("连接失败: %s\n", mysqli_connect_error());
exit();
}

if (
$stmt = $mysqli->prepare("SELECT * FROM sample WHERE t2 LIKE ?")) {
$tt2 = '%';

$stmt->bind_param("s", $tt2);
$stmt->execute();

$meta = $stmt->result_metadata();
while (
$field = $meta->fetch_field())
{
$params[] = &$row[$field->name];
}

call_user_func_array(array($stmt, 'bind_result'), $params);

while (
$stmt->fetch()) {
foreach(
$row as $key => $val)
{
$c[$key] = $val;
}
$result[] = $c;
}

$stmt->close();
}
$mysqli->close();
print_r($result);
?>
34
nieprzeklinaj at gmail dot com
13 年前
我写了一个函数,它可以从结果集中获取所有行,无论结果集是普通的还是准备好的。

<?php
function fetch($result)
{
$array = array();

if(
$result instanceof mysqli_stmt)
{
$result->store_result();

$variables = array();
$data = array();
$meta = $result->result_metadata();

while(
$field = $meta->fetch_field())
$variables[] = &$data[$field->name]; // 引用传递

call_user_func_array(array($result, 'bind_result'), $variables);

$i=0;
while(
$result->fetch())
{
$array[$i] = array();
foreach(
$data as $k=>$v)
$array[$i][$k] = $v;
$i++;

// 不知道为什么,当我尝试 $array[] = $data 时,我在所有行中都得到了相同的结果
}
}
elseif(
$result instanceof mysqli_result)
{
while(
$row = $result->fetch_assoc())
$array[] = $row;
}

return
$array;
}
?>

只需调用它,传递一个结果集或执行的语句,你就可以获取所有被提取的行。
16
andrey at php dot net
18 年前
如果你选择了 LOB,使用以下执行顺序,否则你可能导致 mysqli 分配比实际使用的内存更多

1)prepare()
2)execute()
3)store_result()
4)bind_result()

如果你跳过 3) 或者交换 3) 和 4),那么 mysqli 将为该列的最大长度分配内存,对于 tinyblob 为 255,对于 blob 为 64k(还可以),对于 MEDIUMBLOB 为 16MByte - 非常多,对于 LONGBLOB 为 4G(如果你有这么多的内存很好)。使用这种顺序的查询在有 LOB 时会稍慢,但这是为了避免在几秒钟内出现内存耗尽的代价。
7
quano
13 年前
如果我的结果中有一个 longtext 字段,整个页面将变为空白,没有任何错误提示。这是因为 PHP _崩溃_了。我花了一整个上午才弄清楚这一点。

显然,如果你有 longtext 字段,你必须在使用 bind_result 之前调用 store_result。

http://bugs.php.net/bug.php?id=47928
13
uramihsayibok, gmail, com
15 年前
提醒那些想要返回结果数组的人 - 也就是说,返回查询的所有结果的数组,而不是一次只返回一个。

<?php

// 等等…
call_user_func_array(array($mysqli_stmt_object, "bind_result"), $byref_array_for_fields);

$results = array();
while (
$mysqli_stmt_object->fetch()) {
$results[] = $byref_array_for_fields;
}

?>
这将不起作用。$results 将包含许多数组,但每个数组都将引用 $byref。

PHP 在这里优化性能:你没有将 $byref 数组复制到 $results 中,而是 *添加* 它。这意味着 $results 将包含许多 $byref - 相同的数组重复多次。(所以你看到 $results 是查询中最后一个项目的重复。)

hamidhossain(2008 年 9 月 1 日)展示了如何解决这个问题:在获取结果的循环中,你还需要遍历字段列表,边走边复制。实际上,是单独复制所有内容。

我个人更喜欢使用某种函数来有效地复制数组,而不是编写自己的代码。许多内置的数组函数不起作用,显然是使用引用而不是复制,但 array_map 和 create_function 的组合可以。

<?php

// 等等…
call_user_func_array(array($mysqli_stmt_object, "bind_result"), $byref_array_for_fields);

// 返回值的副本
$copy = create_function('$a', 'return $a;');

$results = array();
while (
$mysqli_stmt_object->fetch()) {
// array_map 在这里和这种方式执行时会保留键
$results[] = array_map($copy, $byref_array_for_fields);
}

?>

如果他们只是为准备好的语句实现了 fetch_assoc 甚至 fetch_array,那么所有这些问题都会消失。
3
atulkashyap1 at hotmail dot com
15 年前
bind_result 也可以用来从函数中返回一组变量。
我花了好长时间才弄明白,所以我想分享一下。

<?php
函数 extracting(){
$query="SELECT topic, detail, date, tags
FROM updates
ORDER BY date DESC
LIMIT 5 "
;
if(
$stmt = $this->conn->prepare($query)) {
$stmt->execute();
$stmt->bind_result($updates[0],$updates[1],$updates[2],$updates[3]);
$i=0;
while(
$stmt->fetch()){
$i++;
$name='t'.$i;
$
$name = array($updates[0],$updates[1],$updates[2],$updates[3]);
}
return array(
$t1,$t2,$t3,$t4,$t5,);
$stmt->close();
}
}
?>
4
kaspy at example dot com
9 年前
对于那些尝试将行绑定到数组的人来说,
<?php
$stmt
= $db->prepare('SELECT id, name, mail, phone, FROM contacts');
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($arr['id'], $arr['name'], $arr['mail'], $arr['phone']);
while (
$stmt->fetch()) {
$outArr[] = $arr;
}
$stmt->close();
return
$outArr;
?>
这将为您提供您请求的所有行,但它们将与第一行相同,因为后台代码中存在一些小错误(据我所知,PHP 正在尝试在此处节省内存)。

但这个有效
<?php
$stmt
= $db->prepare('SELECT id, name, mail, phone, FROM contacts');
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($a,$b,$c,$d);
while (
$stmt->fetch()) {
$outArr[] = ['id' => $a, 'name' => $b, 'mail' => $c, 'phone' => $d];
}
$stmt->close();
return
$outArr;
?>
不要使用数组绑定结果 :)
1
scragar at gmail dot com
13 年前
为了澄清那些在数组方面遇到问题的人,PHP 会自动将数组作为引用传递,并在需要设置或取消设置数组的一部分时克隆数组,更改引用变量不会触发克隆。

这是为了提高效率,要克隆包含此信息的数组,您可以使用 foreach 循环,或者设置/取消设置键。array_values 等技术也可以工作,只要您不介意丢失键。
1
pcc at pccglobal dot com
14 年前
如果操作正确,'call_user_func_array()' 可以将变量绑定到包含 BLOB 列的多列结果。

示例

<?php
$data
= array() ; // 接受数据的数组。
$params = array() ; // 传递给 'bind_result()' 的参数数组
$column = array("fidentity", "fvarchar", "fdate", "ftinyblob") ; // 列名。
foreach($column as $col_name)
{
// 'fetch()' 将获取的值分配给变量 '$data[$col_name]'
$params[] =& $data[$col_name] ;
}
$res = call_user_func_array(array($stmt, "bind_result"), $params) ;
?>

这是完整的示例。
警告:当使用 'prepare' 准备语句来检索 LOB 时,方法顺序很重要。
此外,方法 'store_result()' 必须调用,并且调用顺序必须正确。
未能遵守此操作会导致 PHP/MySQLi 崩溃或返回错误的值。
正确的过程顺序是:prepare -> execute -> store_result -> bind -> fetch

<?php
$database
= "test" ;
$table = "test" ;
$column = array("fidentity", "fvarchar", "fdate", "ftinyblob") ;
$select_set = "`fidentity`, `fvarchar`, `fdate`, `ftinyblob`" ;
$mysqli = new mysqli("localhost", "root", $password, $database);
// 正确的过程顺序:prepare -> execute -> store_result -> bind -> fetch
$stmt = $mysqli->prepare("SELECT $select_set FROM `$table`") ;
$stmt->execute();
$stmt->store_result();
$data = array() ; // 接受数据的数组。
$params = array() ; // 传递给 'bind_result()' 的参数数组
foreach($column as $col_name)
{
// 将获取的值分配给变量 '$data[$name]'
$params[] =& $data[$col_name] ;
}
$res = call_user_func_array(array($stmt, "bind_result"), $params) ;
if(!
$res)
{
echo
"bind_result() 失败: " . $mysqli->error . "\n" ;
}
else
{
$res = $stmt->fetch() ;
if(
$res)
{
echo
"<pre>" . htmlentities(print_r($data, true)) . "</pre>\n" ;
}
else
{
echo ((
false !== $res) ? "数据结束" : $stmt->error) . "\n" ;
}
}
$stmt->close() ;
$mysqli->close() ;
exit ;
?>

上面的示例应该输出
数组 (
[fidentity] => 24
[fvarchar] => the rain in spain
[fdate] => 2010-07-31
[ftinyblob] => GIF89a...(更多 BLOB 数据)
)
5
timchampion dot NOSPAM at gmail dot com
12 年前
只是想确保所有人都知道 get_result,因为那些需要数组格式的结果的人。

在代码示例中,在 execute() 之后,执行一个 get_result(),如下所示

<?php

// ... 此文档的示例代码:

$stmt->execute();

/* 而不是 bind_result: */
$result = $stmt->get_result();

/* 现在您可以将结果提取到一个数组中 - 很棒 */
while ($myrow = $result->fetch_assoc()) {
printf("%s %s\n", $myrow['Code'], $myrow['Name']);
}

?>

当您从查询中获取十几个或更多字段时,这要好得多。希望这有帮助。此外,正如 get_result 的注释中所述,它需要 mysqlnd。
2
Masterkitano
9 年前
对于那些没有 mysqlInd 驱动程序或出于某种原因无法使用 stmt->get_result 的人,我创建了这个函数,它允许您“模拟”mysqli_result::fetch_assoc

函数 fetchAssocStatement($stmt)
{
如果($stmt->num_rows>0)
{
$result = 数组();
$md = $stmt->result_metadata();
$params = 数组();
while($field = $md->fetch_field()) {
$params[] = &$result[$field->name];
}
call_user_func_array(array($stmt, 'bind_result'), $params);
$stmt->fetch();
返回 $result;
}

返回 null;
}

您可以在 while 语句中使用它来从语句中提取并返回一个关联数组(只要语句是打开的)
用法
$statement = $mysqli->prepare($query));
$statement.execute();
while($rowAssocArray = fetchAssocStatement($statement))
{
//做点什么
}

$statement.close();

希望这有帮助。
1
carloshritzmann at gmail dot com
2 年前
从 PHP 7.4+ 开始,您可以使用扩展运算符 (...) 来自动将变量分配给查询语句,并在使用预处理语句执行 SELECT 请求时提取数据。

但是,扩展运算符会考虑数组的大小。因此,它必须在任何上下文中使用之前预先分配。

<?php
$link
= // 创建数据库连接

$query_text = "SELECT mission, year, report FROM table WHERE id=? AND name=?;";

// 要分配的数据
$types = "is";
$param = [0, "John Titor"];

// 准备并执行语句
$stmt = mysqli_stmt_prepare($link, $query_text);
if (
mysqli_stmt_execute($stmt)) {

// 我们知道我们将检索 3 列:Mission、Year 和 Report。
$output = [0, 0, 0];

// 在幕后,扩展运算符在使用时会给出这个想法:
// mysqli_stmt_bind_result($link, $output[0], $output[1], $output[2]);
mysqli_stmt_bind_result($stmt, ...$output);

// 提取数据
while (mysqli_stmt_fetch($stmt)) {
echo
"Mission: " . $output[0] . "\n";
echo
"Year: " . $output[1] ."\n";
echo
"Report: " . $output[2] . "\n";
}

} else {
echo
"Error: Wrong Timeline\n";
}

// 关闭数据库连接
?>
1
dev+php at alepe dot com
13 年前
根据上面的文档
"根据绑定变量的列类型,它们可能会静默更改为相应的 PHP 类型。"

如果将字段指定为 int(tinyint、mediumint 等)并具有 zerofill 属性,它将(静默)转换为 PHP 整数(擦除前导零)。为了保留这些前导零,一种解决方案是将字段指定为 decimal。

请注意,这仅在使用预处理语句时才会发生,而不会在直接执行查询时发生。
1
Miguel Hatrick
15 年前
从这里获取了一些很酷的代码,并为那些面向对象的家伙创建了一个小类

像这样使用

<?php
// 执行预处理语句
$stmt->execute();
$stmt->store_result();

// 自定义类 :D 绑定到语句结果 mambo jambo!
$sr = new Statement_Result($stmt);

$stmt->fetch();
printf("ID: %d\n", $sr->Get('id') );

/////////////////////////////////

class Statement_Result
{
private
$_bindVarsArray = array();
private
$_results = array();

public function
__construct(&$stmt)
{
$meta = $stmt->result_metadata();

while (
$columnName = $meta->fetch_field())
$this->_bindVarsArray[] = &$this->_results[$columnName->name];

call_user_func_array(array($stmt, 'bind_result'), $this->_bindVarsArray);

$meta->close();
}

public function
Get_Array()
{
return
$this->_results;
}

public function
Get($column_name)
{
return
$this->_results[$column_name];
}
}
?>
1
bb at servertje dot nl
16 年前
虽然受到早期帖子的启发,但此方法可以添加到您的任何数据库对象中。它是早期帖子的面向对象实现。

该方法返回一个数组,其中包含表示行的对象。每个属性都表示一个列及其值。

<?php
private function getresult($stmt)
{
$result = array();

$metadata = $stmt->result_metadata();
$fields = $metadata->fetch_fields();

for (;;)
{
$pointers = array();
$row = new stdClass();

$pointers[] = $stmt;
foreach (
$fields as $field)
{
$fieldname = $field->name;
$pointers[] = &$row->$fieldname;
}

call_user_func_array(mysqli_stmt_bind_result, $pointers);

if (!
$stmt->fetch())
break;

$result[] = $row;
}

$metadata->free();

return
$result;
}
?>
0
brad dot jackson at resiideo dot com
19 年前
从预处理语句绑定结果参数时,存在一个潜在问题,这些参数引用了 mediumblobs 等大型数据类型。我们其中一个数据库表包含一个二进制图像数据表。此表中最大的图像大约为 50Kb,但即使如此,列的类型也为 mediumblob,以便允许大于 64Kb 的文件。我花了令人沮丧的一个小时试图找出为什么 mysqli_stmt_bind_result 在尝试为应该最多为 50Kb 的结果分配 16MB 的内存时窒息,直到我意识到该函数首先检查列类型以找出可能检索到的结果大小,并尝试分配这么多内存来容纳它。我的解决方案是使用更基本的 mysqli_result() 查询。另一个选择可能是将图像数据列的类型重新设置为 blob(64Kb 限制)。
-2
thejkwhosaysni at gmail dot com
18 年前
我创建了这些函数,它们将像 mysqli_fetch_array() 和 mysqli_fetch_object() 一样工作,但使用绑定结果。

<?php
function fetch_object() {
$data = mysqli_stmt_result_metadata($this->stmt);
$count = 1; // 从 1 开始计数。第一个值必须是 stmt 的引用。
$fieldnames[0] = &$this->stmt;
$obj = new stdClass;
while (
$field = mysqli_fetch_field($data)) {
$fn = $field->name; // 获取所有字段名称
$fieldnames[$count] = &$obj->$fn; // 将字段名加载到对象中。
$count++;
}
call_user_func_array(mysqli_stmt_bind_result, $fieldnames);
mysqli_stmt_fetch($this->stmt);
return
$obj;
}

function
fetch_array() {
$data = mysqli_stmt_result_metadata($this->stmt);
$count = 1; // 从 1 开始计数。第一个值必须是 stmt 的引用,因为 bind_param 要求 $stmt 的链接作为第一个参数。
$fieldnames[0] = &$this->stmt;
while (
$field = mysqli_fetch_field($data)) {
$fieldnames[$count] = &$array[$field->name]; // 将字段名加载到数组中。
$count++;
}
call_user_func_array(mysqli_stmt_bind_result, $fieldnames);
mysqli_stmt_fetch($this->stmt);
return
$array;

}

?>

希望这对某些人有帮助,我被这个问题困扰了一段时间。
To Top