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() 將返回 false。可以使用 mysqli_stmt_errno() 函式來區分返回 false 的兩種原因;由於錯誤,在 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 則註解

匿名
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;
}
?>

希望這能幫助到其他人。
匿名
6 年前
拜託,真的拜託。
我試著從這個函式取得結果集,但是將近三個小時都完全沒有成果!

如果你正在使用 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_ AND 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 也沒有提供我答案!
jeffspicer at gmail dot com
6 年前
為了避免其他人花費數小時尖叫,試圖找出為什麼在啟用原生驅動程式時卻無法運作的原因。這是因為如果你想使用這個功能,你需要確保在伺服器上同時啟用原生驅動程式 mysqlnd 和 nd_mysqli。

否則,僅啟用 mysqlnd 原生驅動程式並不會包含 mysqli_stmt_get_result 函式,因為它顯然位於 nd_mysqli 原生驅動程式中。遺憾的是,大多數文件只提到 mysqlnd 原生驅動程式。

一旦你啟用了這兩個原生驅動程式,這個函式就會如文件所述般運作。
jari dot wiklund at gmail dot com
13 年前
請注意,此方法需要 mysqlnd 驅動程式。否則你會收到以下錯誤:Call to undefined method mysqli_stmt::get_result()(呼叫未定義的方法 mysqli_stmt::get_result())
Haravikk
8 年前
對於有興趣的人來說,這個函式似乎總是會產生一個已儲存的結果,使其等同於 mysqli::store_result(),而不是像 mysqli::use_result() 那樣按需擷取。

這一點很重要,因為這表示你無法像通常那樣,透過在擷取之前呼叫 mysqli_stmt::store_result() 來控制結果的性質,這也是我個人的預期。

因此,如果你想要模擬 mysqli::use_result() 的行為,你仍然需要使用 mysqli_stmt::bind_param() 和 mysqli_stmt::fetch()。
HeadlessDev
5 年前
感謝所有留下筆記的人,沒有你們我無法完成我的工作。我在這個頁面和其他頁面筆記的幫助下編寫了這個函數。

我沒有 mysqlnd 可用,但希望能夠以物件的形式取得查詢的 get_result()。

請注意:我不是 PHP 專家

以下是如何使用我的 get_result() 函數來登入用戶的範例
<?php
//Sanitize input before using this function
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); //USING FUNCTION HERE
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();
//If we get here they are not logged in
return false;
}

//Returns an array with each row as an object
function get_result($stmt){
$stmt->execute(); //Execute query
$stmt->store_result(); //Store the results
$num_rows = $stmt->num_rows; //Get the number of results
$results = NULL;
if(
$num_rows > 0){
//Get metadata about the results
$meta = $stmt->result_metadata();
//Here we get all the column/field names and create the binding code
$bind_code = "return mysqli_stmt_bind_result(\$stmt, ";
while(
$_field = $meta->fetch_field()){
$bind_code .= "\$row[\"".$_field->name."\"], ";
}
//Replace trailing ", " with ");"
$bind_code = substr_replace($bind_code,");", -2);
//Run the code, if it doesn't work return NULL
if(!eval($bind_code)) {
$stmt->close();
return
NULL;
}
//This is where we create the object and add it to our final result array
for($i=0;$i<$num_rows;$i++){
//Gets the row by index
$stmt->data_seek($i);
//Update bound variables used in $bind_code with new row values
$stmt->fetch();
foreach(
$row as $key=>$value){
//Create array using the column/field name as the index
$_result[$key] = $value;
}
//Cast $_result to object and append to our final results
$results[$i] = (object)$_result;
}
}
$stmt->close();
return
$results;
}
?>
To Top