就像 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://www.php.net/manual/zh/book.mysqli.php
各自媒體平臺均可搜索【硬核項目經理】