PHP Conference Japan 2024

mysqli_stmt::get_result

mysqli_stmt_get_result

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

mysqli_stmt::get_result -- mysqli_stmt_get_result将预处理语句的结果集作为mysqli_result 对象获取

描述

面向对象风格

public mysqli_stmt::get_result(): mysqli_result|false

过程化风格

mysqli_stmt_get_result(mysqli_stmt $statement): mysqli_result|false

将预处理语句的结果集作为mysqli_result 对象检索。数据将从MySQL服务器提取到PHP。此方法应仅用于生成结果集的查询。

注意:

仅适用于 mysqlnd

注意:

此函数不能与mysqli_stmt_store_result()一起使用。这两个函数都从MySQL服务器检索完整的结果集。

参数

statement

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

返回值

失败时返回false。对于生成结果集的成功查询(例如SELECT, SHOW, DESCRIBEEXPLAIN),mysqli_stmt_get_result() 将返回一个mysqli_result 对象。对于其他成功查询,mysqli_stmt_get_result() 将返回falsemysqli_stmt_errno() 函数可用于区分导致false的两个原因;由于bug,在PHP 7.4.13之前,必须使用mysqli_errno()来实现此目的。

错误/异常

如果启用了mysqli错误报告 (MYSQLI_REPORT_ERROR),并且请求的操作失败,则会生成警告。如果此外模式设置为MYSQLI_REPORT_STRICT,则会抛出mysqli_sql_exception

示例

示例 #1 面向对象风格

<?php

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

$query = "SELECT Name, Population, Continent FROM Country WHERE Continent=? ORDER BY Name LIMIT 1";

$stmt = $mysqli->prepare($query);
$stmt->bind_param("s", $continent);

$continentList = array('Europe', 'Africa', 'Asia', 'North America');

foreach (
$continentList as $continent) {
$stmt->execute();
$result = $stmt->get_result();
while (
$row = $result->fetch_array(MYSQLI_NUM)) {
foreach (
$row as $r) {
print
"$r ";
}
print
"\n";
}
}

示例 #2 过程化风格

<?php

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

$query = "SELECT Name, Population, Continent FROM Country WHERE Continent=? ORDER BY Name LIMIT 1";

$stmt = mysqli_prepare($link, $query);
mysqli_stmt_bind_param($stmt, "s", $continent);

$continentList= array('Europe', 'Africa', 'Asia', 'North America');

foreach (
$continentList as $continent) {
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
while (
$row = mysqli_fetch_array($result, MYSQLI_NUM)) {
foreach (
$row as $r) {
print
"$r ";
}
print
"\n";
}
}

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

Albania 3401200 Europe 
Algeria 31471000 Africa 
Afghanistan 22720000 Asia 
Anguilla 8000 North America

参见

添加备注

用户贡献的备注 6 条备注

47
匿名用户
11 年前
我在一台没有安装 mysqlnd 的服务器上遇到了很多麻烦,并且有很多头痛的问题。

如果您没有安装/加载 mysqlnd,则在尝试调用“mysqli_stmt_get_result()”时会得到未定义的引用。

我编写了自己的 mysqli_stmt_get_result() 和 mysqli_result_fetch_array() 来配合使用。

<?php
class iimysqli_result
{
public
$stmt, $nCols;
}

function
iimysqli_stmt_get_result($stmt)
{
/** 解释:
* 我们正在创建一个伪造的“结果”结构,使我们能够拥有
* 与通过
* mysqli_query() 执行的查询在源代码级别上等效的语法。
*
* $stmt = mysqli_prepare($conn, "");
* mysqli_bind_param($stmt, "types", ...);
*
* $param1 = 0;
* $param2 = 'foo';
* $param3 = 'bar';
* mysqli_execute($stmt);
* $result _mysqli_stmt_get_result($stmt);
* [ $arr = _mysqli_result_fetch_array($result);
* || $assoc = _mysqli_result_fetch_assoc($result); ]
* mysqli_stmt_close($stmt);
* mysqli_close($conn);
*
* 在源代码级别上,这与 mysqlnd 没有区别。
**/
$metadata = mysqli_stmt_result_metadata($stmt);
$ret = new iimysqli_result;
if (!
$ret) return NULL;

$ret->nCols = mysqli_num_fields($metadata);
$ret->stmt = $stmt;

mysqli_free_result($metadata);
return
$ret;
}

function
iimysqli_result_fetch_array(&$result)
{
$ret = array();
$code = "return mysqli_stmt_bind_result(\$result->stmt ";

for (
$i=0; $i<$result->nCols; $i++)
{
$ret[$i] = NULL;
$code .= ", \$ret['" .$i ."']";
};

$code .= ");";
if (!eval(
$code)) { return NULL; };

// 这应该会推进“$stmt”游标。
if (!mysqli_stmt_fetch($result->stmt)) { return NULL; };

// 返回我们构建的数组。
return $ret;
}
?>

希望这对某些人有所帮助。
22
匿名用户
6 年前
拜托了!
我一直在尝试从这个函数中获取结果集,但我完全没有成功,花了将近 3 个小时!

如果您正在使用 mysqli_stmt_get_results() 获取结果集,并结合使用 mysqli_stmt_store_results 来检索返回的行数,您将会遇到一些重大问题!

PHP 文档指出,要检索预处理 select sql 语句返回的行数,应该分别调用以下语句

mysqli_stmt_execute($stmt);
mysqli_stmt_store_result($stmt);
$num_rows = mysqli_stmt_num_rows($stmt);

如果您同时使用 mysqli_stmt_get_result(),这将是一个巨大的陷阱!!结果因您首先调用的语句而异,但最终您将无法获得所需的结果。

总之,请千万不要同时使用 mysqli_stmt_store_result(),然后是 mysqli_ 和 mysqli_stmt_get_result()。这是一个巨大的陷阱。

解决方案
如果您尝试获取结果集,并且同时需要返回的行数,请分别使用以下语句:

$result_set = mysqli_stmt_get_results($stmt);
$num_rows = mysqli_num_rows($result_set);

反思我的行为,这个解决方案可能看起来相当明显。但是,对于使用 PHP 的新手(像我一样)或不完全熟悉预处理语句的人来说,很容易通过使用 Google 和自学而迷失方向。

总结
切勿同时使用 mysqli_stmt_store_result($stmt) & mysqli_stmt_num_rows($stmt) 和 mysqli_stmt_get_result($stmt)。你会后悔的!!我被这个问题困扰了好几个小时,Google 也无法提供答案!
6
jeffspicer at gmail dot com
6 年前
为了防止其他人因弄清楚为什么在启用本机驱动程序时此功能不起作用而花费数小时的时间大喊大叫。这是因为如果您希望使用此功能,则需要确保在服务器上启用本机驱动程序 mysqlnd 和 nd_mysqli。

否则,仅启用 mysqlnd 本机驱动程序并不包含 mysqli_stmt_get_result 函数,因为此函数显然位于 nd_mysqli 本机驱动程序中。不幸的是,大多数文档只讨论 mysqlnd 本机驱动程序。

启用这两个本机驱动程序后,此函数即可按文档说明工作。
24
jari dot wiklund at gmail dot com
13 年前
请注意,此方法需要 mysqlnd 驱动程序。否则,您将收到此错误:调用未定义的方法 mysqli_stmt::get_result()
1
Haravikk
8 年前
对于感兴趣的人来说,此函数似乎总是产生存储结果,使其等效于 mysqli::store_result(),而不是像 mysqli::use_result() 那样按需提取。

这很重要,因为它意味着您无法像通常那样通过在提取之前调用 mysqli_stmt::store_result() 来控制结果的性质,正如我个人预期的那样。

因此,如果您想模拟 mysqli::use_result() 的行为,您仍然需要使用 mysqli_stmt::bind_param() 和 mysqli_stmt::fetch()。
1
HeadlessDev
5 年前
感谢所有留下笔记的人,没有你们的笔记,我将无法完成我的工作。我是在参考了本页和其他页面上的笔记后编写了这个函数。

我没有 mysqlnd 可用,但想能够将查询的 `get_result()` 获取为对象。

请注意:我不是 PHP 专家

这是一个使用我的 `get_result()` 函数进行用户登录的示例
<?php
// 使用此函数前请先对输入进行安全处理
function login($email, $password){
require
'connect_db.php';
$query = $sql->stmt_init();
if(
$query->prepare("SELECT CustomerId, Password, Admin FROM users WHERE Email = ?")){
$query->bind_param("s",$email);
$result = get_result($query); // 在此处使用函数
if($result != NULL){
$user = $result[0];
if(
password_verify($password, $user->Password)){
$_SESSION['user_id'] = $user->CustomerId;
if(
$user->Admin == 1){
$_SESSION['admin'] = true;
}
$sql->close();
return
true;
}
}
}
$sql->close();
// 如果到达此处,则表示用户未登录
return false;
}

// 返回一个数组,其中每一行都是一个对象
function get_result($stmt){
$stmt->execute(); // 执行查询
$stmt->store_result(); // 存储结果
$num_rows = $stmt->num_rows; // 获取结果数
$results = NULL;
if(
$num_rows > 0){
// 获取结果的元数据
$meta = $stmt->result_metadata();
// 在这里我们获取所有列/字段名并创建绑定代码
$bind_code = "return mysqli_stmt_bind_result(\$stmt, ";
while(
$_field = $meta->fetch_field()){
$bind_code .= "\$row[\"".$_field->name."\"], ";
}
// 将尾随的 ", " 替换为 ");"
$bind_code = substr_replace($bind_code,");", -2);
// 运行代码,如果失败则返回 NULL
if(!eval($bind_code)) {
$stmt->close();
return
NULL;
}
// 在这里我们创建对象并将其添加到最终结果数组
for($i=0;$i<$num_rows;$i++){
// 通过索引获取行
$stmt->data_seek($i);
// 使用新行值更新在 $bind_code 中使用的绑定变量
$stmt->fetch();
foreach(
$row as $key=>$value){
// 使用列/字段名作为索引创建数组
$_result[$key] = $value;
}
// 将 $_result 转换为对象并添加到最终结果
$results[$i] = (object)$_result;
}
}
$stmt->close();
return
$results;
}
?>
To Top