PHP中的MySQLi擴展學習(五)MySQLI_STMT對象操作 https://www.php.net/manual/zh/book.mysqli.php

就像 PDO 中的 PDO_Statment 對象一樣,MySQLI_STMT 對象也是一個預處理語句所形成的對象,專門用來操作 MySQLi 所生成的預處理語句的。其實操作方式之類也都比較相似,不外乎以綁定參數爲主的一些針對 SQL 語句和獲取結果集的操作。

參數綁定及操作屬性

之前的文章中想必大家已經見過我們使用的 bind_param() 方法,它與 PDO 中的 bindParam() 方法有很大的不同。

$stmt = $mysqli->prepare("insert into zyblog_test_user(username, password, salt) values(?, ?, ?)");

$username='mysqli_username';
$password='mysqli_password';
$salt = 'mysqli_salt';
$stmt->bind_param('sss', $username, $password, $salt);

var_dump($stmt->insert_id); // int(232)
var_dump($stmt->affected_rows); // int(1)

$stmt->execute();

$stmt->close();

首先就是之前提到過的,MySQLI_STMT 中綁定參數只能使用 ? 問號佔位符,然後在使用 bind_param() 時,使用的是 's' 這種來按順序綁定參數,這個 's' 代表的就是字符串。另外還可以是 'i' 表示整型數字、'd' 表示浮點數字、 'b' 表示 blob 類型。

另外,從上面的測試代碼中還可以看出,可以使用一個 bind_param() 方法綁定多個參數,'sss' 就是三個字符串,按順序進行綁定。

綁定參數之後,我們就可以通過 execute() 方法來執行語句。同 PDO 一樣,這個方法只返回成功失敗的信息,也就是一個布爾值。所以,我們需要通過 MySQLI_STMT 對象的 insert_id 來獲得新增加數據的 ID ,或者通過 affected_rows 屬性來獲得當前語句執行後影響的行數,來確定語句是否真正地執行完成並達到我們的期望。

最後,我們使用 close() 關閉一個當前的 STMT 對象。這樣在後面的操作中上面的 $stmt 對象就無法使用了。

接下來,我們看看如果綁定了錯誤的類型會怎麼樣,以及 MySQLI_STMT 中關於錯誤信息的提示。

$stmt = $mysqli->prepare("insert into zyblog_test_user(id, username, password, salt) values(?, ?, ?, ?)");

$id = 's';
$username='mysqli_username';
$password='mysqli_password';
$salt = 'mysqli_salt';
$stmt->bind_param('isss', $username, $password, $salt);
$stmt->execute();


var_dump($stmt->errno); // int(2031)
var_dump($stmt->error); // string(53) "No data supplied for parameters in prepared statement"
var_dump($stmt->error_list);
// array(1) {
//     [0]=>
//     array(3) {
//       ["errno"]=>
//       int(2031)
//       ["sqlstate"]=>
//       string(5) "HY000"
//       ["error"]=>
//       string(53) "No data supplied for parameters in prepared statement"
//     }
//   }

$stmt->close();

在代碼中,我們增加了 id 參數的綁定,然後指定的類型是 'i' ,但是,我們實際傳遞的變量是一個字符串類型,結果就會導致 MySQLI_STMT 產生錯誤。

可以看出,MySQLI_STMT 的錯誤屬性和信息基本和 MySQLi 對象的是一樣的。

列綁定

除了請求查詢語句參數的綁定之外,MySQLI_STMT 也是支持直接綁定列的。就和 PDO 中的 bindColumn() 一樣。

$stmt = $mysqli->prepare("select * from zyblog_test_user where username = ?");

$username = 'kkk';
$stmt->bind_param("s", $username); // 綁定參數
$stmt->bind_result($col1, $col2, $col3, $col4);
$stmt->execute(); // 執行語句

var_dump($stmt);
// object(mysqli_stmt)#2 (10) {
//     ["affected_rows"]=>
//     int(-1)
//     ["insert_id"]=>
//     int(0)
//     ["num_rows"]=>
//     int(0)
//     ["param_count"]=>
//     int(1)
//     ["field_count"]=>
//     int(4)
//     ["errno"]=>
//     int(0)
//     ["error"]=>
//     string(0) ""
//     ["error_list"]=>
//     array(0) {
//     }
//     ["sqlstate"]=>
//     string(5) "00000"
//     ["id"]=>
//     int(3)
//   }

while($stmt->fetch()){
    printf("%s %s %s %s", $col1, $col2, $col3, $col4);
    echo PHP_EOL;
}
// 42 kkk 666 k6
// 43 kkk 666 k6
// ……

var_dump($stmt->num_rows); // int(7)

$stmt->close();

當然,方法的名稱還是有些變動的。MySQLI_STMT 中綁定列的方法名爲 bind_result() ,雖說名字不一樣,但功能其實都是差不多的,查詢語句中是幾個列名,就要綁定幾個列名。在這個表中,我們有四個字段,所以通過引用傳遞的方式綁定了 4 個列變量。當使用 fetch() 進行查詢結果對象的遍歷時,就像使用引用的方式爲這 4 個列變量賦值。

在這段代碼中,我們使用了 num_rows 這個屬性來獲得查詢結果的行數量,這個屬性是隻針對 SELECT 語句的。上面介紹過的 affected_rows 是受影響的行數,這兩個屬性不是相同的概念哦!

返回結果集

執行 fetch() 方法返回的是一個布爾值,它主要的作用是將結果集綁定到指定的變量中,所以如果你直接打印它的結果是不會有什麼有用的信息的,我們必須通過綁定列變量的方式來獲得數據。而真正獲得結果集的數據其實是通過另一個方法來獲得一個 MySQLI_result 對象,然後再使用這個對象裏面的方法就可以像 PDO 的 fetch() 一樣來獲得真正的結果集了。

$stmt = $mysqli->prepare("select * from zyblog_test_user where username = 'kkk'");

$stmt->execute(); // 執行語句
$result = $stmt->get_result();


while($row = $result->fetch_assoc()){
    var_dump($row);
}
// array(4) {
//     ["id"]=>
//     int(42)
//     ["username"]=>
//     string(3) "kkk"
//     ["password"]=>
//     string(3) "666"
//     ["salt"]=>
//     string(2) "k6"
//   }
// ……

$stmt->close();

在這裏,我們通過 get_result() 方法獲得了一個結果集的 MySQLI_result 對象。然後通過該對象的 fetch_assoc() 就獲得了鍵名形式的結果集數組。

關於 MySQLI_result 對象的內容,我們將在下篇文章中再進行詳細的學習瞭解。

保存結果集及遊標移動

最後就是關於遊標的移動,上面的測試數據中我們可以查詢到 7 條數據,並且第一條數據的 id 是 42 ,通過遊標,我們可以不在 SQL 語句中使用 limit 而直接操作結果集來獲取需要的數據。

$stmt = $mysqli->prepare("select * from zyblog_test_user where username = 'kkk'");

$stmt->bind_result($col1, $col2, $col3, $col4);
$stmt->execute(); // 執行語句
$stmt->store_result();
// 一共7條,從第5個開始
$stmt->data_seek(5);
$stmt->fetch();
printf("%s %s %s %s", $col1, $col2, $col3, $col4); // 47 kkk 666 k6
echo PHP_EOL;

$stmt->close();

首先,我們需要使用 store_result() 方法來將結果集保存到內存中,這個方法和 MySQLi 中的 store_result() 方法是一樣的。然後,通過 data_seek() 方法將遊標移動 5 個位置,最後輸出的結果就是後面那兩條數據的內容了。是不是很高大上的感覺!

總結

關於 MySQLI_STMT 對象的內容還有一些,不過就不是那麼常用了。從我們講解的這些內容也可以看出它和 PDO 的許多不同之處。當然,總體的大方向基本還是一致的,所以我們學習起來也並不會有太大的困難,掌握理解之後更多的還是要動手操作,基本功可千萬不能荒廢哦!

測試代碼:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202009/source/8.PHP中的MySQLi擴展學習(五)MySQLI_STMT對象操作.php

參考文檔:

https://www.php.net/manual/zh/book.mysqli.php

各自媒體平臺均可搜索【硬核項目經理】

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章