搜尋
首頁後端開發PHP問題三分鐘帶你了解PHP中的查詢結構集

本篇文章要為大家介紹一下PHPPHP中的查詢結構集。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。

三分鐘帶你了解PHP中的查詢結構集

PHP中的PDO操作學習(四)查詢結構集

關於PDO 的最後一篇文章,我們就以查詢結果集的操作為結束。在資料庫的操作中,查詢往往佔的比例非常高。在日常的開發中,大部分的業務都是讀多寫少型的業務,所以掌握好查詢相關的操作是我們學習的重要內容。和 mysqli 一樣,PDO 對於查詢的支援也是非常方便快速的,透過幾個函數就可以非常方便且有效率地操作各種查詢語句。

在使用預處理語句的情況下,我們使用 execute() 執行之後,查詢的結果集就會儲存在 PDOStatement 物件中。對於資料的操作就轉移到了 PHP 的物件中,所以我們需要 PDOStatement 的一些方法來獲得結果集的內容。

fetch() 方法

透過 fetch() 方法,得到的是查詢結果集的下一行。

$stmt = $pdo->prepare("select * from zyblog_test_user");
$stmt->execute();

$row = $stmt->fetch();
print_r($row);
// Array
// (
//     [id] => 1
//     [0] => 1
//     [username] => aaa
//     [1] => aaa
//     [password] => aaa
//     [2] => aaa
//     [salt] => aaa
//     [3] => aaa
// )

從傳回的結果來看,我們沒有給 PDO 物件指定 PDO::ATTR_DEFAULT_FETCH_MODE 屬性,所以它是傳回的預設的 PDO::FETCH_BOTH 格式,也就是欄位名稱和下標同時存在的。其實這個方法可以直接指定我們需要的 FETCH_STYLE 。

結果集類型指定

$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
// Array
// (
//     [id] => 2
//     [username] => bbb
//     [password] => bbb
//     [salt] => 123
// )

$row = $stmt->fetch(PDO::FETCH_LAZY);
print_r($row);
// PDORow Object
// (
//     [queryString] => select * from zyblog_test_user
//     [id] => 3
//     [username] => ccc
//     [password] => bbb
//     [salt] => c3
// )

$row = $stmt->fetch(PDO::FETCH_OBJ);
print_r($row);
// stdClass Object
// (
//     [id] => 4
//     [username] => ccc
//     [password] => bbb
//     [salt] => c3
// )

和指定 PDO 物件的 PDO::ATTR_DEFAULT_FETCH_MODE 一樣。使用 fetch() 方法時直接將需要的回傳結果類型參數指定到方法的第一個參數,就實作了 FETCH_STYLE 的指定。具體支援的格式和之前講過的 PDO 物件的 PDO::ATTR_DEFAULT_FETCH_MODE 屬性是完全一樣的,大家可以自行查閱。

取得全部資料

從程式碼和定義可以看出,fetch() 方法是取得目前資料集的下一行數據,就像資料庫的遊標操作一樣。所以,我們可以透過循環 fetch() 來對結果集進行遍歷,從而獲得所有的結果集資料。

 while($row = $stmt->fetch()){
    print_r($row);
}
// Array
// (
//     [id] => 2
//     [0] => 2
//     [username] => bbb
//     [1] => bbb
//     [password] => bbb
//     [2] => bbb
//     [salt] => 123
//     [3] => 123
// )
// ……

MySQL 不支援遊標

上文中提到了遊標操作,PDO 擴充功能是支援遊標的,但是需要注意的是,MySQL 擴充功能並不支援這個操作。所以我們使用遊標相關的屬性對於 MySQL 函式庫是沒有效果的。

$stmt = $pdo->prepare("select * from zyblog_test_user", [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);
$stmt->execute();

$row = $stmt->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT);
print_r($row);
// Array
// (
//     [id] => 1
//     [username] => aaa
//     [password] => aaa
//     [salt] => aaa
// )

$stmt = $pdo->prepare("select * from zyblog_test_user", [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);
$stmt->execute();

$row = $stmt->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_LAST);
print_r($row);
// Array
// (
//     [id] => 1
//     [username] => aaa
//     [password] => aaa
//     [salt] => aaa
// )

如果是支援遊標操作的資料庫及擴充的話,上面程式碼中的 fetch() 的第二個參數指定後,所獲得的結果是會不同的。 PDO::FETCH_ORI_NEXT 是取得遊標的下一筆數據,而 PDO::FETCH_ORI_LAST 是取得遊標的最後一筆資料。但在我們對 MySQL 的測試中,它們並沒有任何效果,依然是取得結果集的下一個資料。

fetchAll() 方法

透過fetch() 方法,我們可以獲得結果集中的全部數據,不過還是需要一個循環才能進行遍歷,多少還是有點麻煩。其實,PDO 早就為我們準備好了另一個方法,fetchAll() 就是傳回一個包含結果集中所有行的陣列。

$stmt = $pdo->prepare("select * from zyblog_test_user limit 2");
$stmt->execute();

$list = $stmt->fetchAll();
print_r($list);
// Array
// (
//     [0] => Array
//         (
//             [id] => 1
//             [0] => 1
//             [username] => aaa
//             [1] => aaa
//             [password] => aaa
//             [2] => aaa
//             [salt] => aaa
//             [3] => aaa
//         )

//     [1] => Array
//         (
//             [id] => 2
//             [0] => 2
//             [username] => bbb
//             [1] => bbb
//             [password] => bbb
//             [2] => bbb
//             [salt] => 123
//             [3] => 123
//         )

// )

fetchAll() 就是在內部使用了 fetch() 幫我們遍歷了一次結果集並且賦值到了一個陣列中。所以我們如果在不重新 execute() 情況下再次呼叫 fetchAll() 的話,取得的就是空的資料。因為遊標已經到底了。

$list = $stmt->fetchAll();
print_r($list);
// Array
// (
// )

它同樣支援指定 FETCH_STYLE ,也和 fetch() 方法一樣,直接將所需的型別常數賦值給第一個參數就可以了。

// PDO::FETCH_ASSOC
$stmt = $pdo->prepare("select * from zyblog_test_user limit 2");
$stmt->execute();

$list = $stmt->fetchAll(PDO::FETCH_ASSOC);
print_r($list);
// Array
// (
//     [0] => Array
//         (
//             [id] => 1
//             [username] => aaa
//             [password] => aaa
//             [salt] => aaa
//         )

//     [1] => Array
//         (
//             [id] => 2
//             [username] => bbb
//             [password] => bbb
//             [salt] => 123
//         )

// )

// PDO::FETCH_COLUMN
$stmt = $pdo->prepare("select * from zyblog_test_user limit 2");
$stmt->execute();

$list = $stmt->fetchAll(PDO::FETCH_COLUMN, 1);
print_r($list);
// Array
// (
//     [0] => aaa
//     [1] => bbb
// )

// PDO::FETCH_CLASS
class User{
    function __construct($a){
        echo $a, PHP_EOL;
    }
}
$stmt = $pdo->prepare("select * from zyblog_test_user limit 2");
$stmt->execute();
$list = $stmt->fetchAll(PDO::FETCH_CLASS, 'User', ['FetchAll User']);
print_r($list);
// FetchAll User
// FetchAll User
// Array
// (
//     [0] => User Object
//         (
//             [id] => 1
//             [username] => aaa
//             [password] => aaa
//             [salt] => aaa
//         )

//     [1] => User Object
//         (
//             [id] => 2
//             [username] => bbb
//             [password] => bbb
//             [salt] => 123
//         )

// )

是不是非常熟悉了,這裡就不多講了,關於FETCH_STYLE 的類型指定已經說過很多遍了,它的用法和fetch() 以及PDO 對像中的query() 方法都是差不多的。不過它也支援一種以回調方式呼叫一個方法的形式來獲得資料集。

function getValue(){
    print_r(func_get_args());
}
// Array
// (
//     [0] => 1
//     [1] => aaa
//     [2] => aaa
//     [3] => aaa
// )
// Array
// (
//     [0] => 2
//     [1] => bbb
//     [2] => bbb
//     [3] => 123
// )
$stmt = $pdo->prepare("select * from zyblog_test_user limit 2");
$stmt->execute();
$list = $stmt->fetchAll(PDO::FETCH_FUNC, 'getValue');
print_r($list);
// Array
// (
//     [0] => 
//     [1] => 
// )

在這段程式碼中,我們使用的是 PDO::FETCH_FUNC ,第二個參數是一個方法名稱。這樣每一條結構集都會在遍歷的時候當作方法的參數去呼叫指定的這個方法,我們透過 func_get_args() 就可以取得這些參數內容。在這段程式碼中,結果集並不會透過 fetchAll() 方法的回傳值賦值給 $list 變數了。因為資料都已經傳遞給了指定的 getValue() 方法了。

fetchColumn() 方法

在上面的測試程式碼中,我們使用過 PDO::FETCH_COLUMN 來取得結果集的某一列資料。這樣寫沒什麼問題,但有更方便的方式,也就是 PDOStatment 直接提供給我們的一個 fetchColumn() 方法。它就相當於是預設的在方法內部指定了 PDO::FETCH_COLUMN ,並且只需要一個參數就是列的下標。

要注意的是,它的回傳是下一行的指定列值,也就是說,它在底層是呼叫的 fetch() 方法。如果要取得結果集中所有指定列的內容,我們還需要透過和 fetch() 的遍歷方式一樣的方法來遍歷結果集。

// fetchColumn
$stmt = $pdo->prepare("select * from zyblog_test_user");
$stmt->execute();
$column = $stmt->fetchColumn(2);
echo $column, PHP_EOL;
// aaa

$column = $stmt->fetchColumn(3);
echo $column, PHP_EOL;
// 123

fetchObject() 方法

fetchObject() 就不用多解释了,它和 fetchColumn() 是类似的,只是返回的是下一行数据的对象格式。同样的,它也是可以传递构造参数的,这点和 PDO 对象的 query() 中指定的 PDO::FETCH_CLASS 格式的使用是一样的。我们在第一篇文章中就有讲解。

// fetchObject
$stmt = $pdo->prepare("select * from zyblog_test_user");
$stmt->execute();
$user = $stmt->fetchObject('User', ['FetchObject User']);
print_r($user);
// FetchObject User
// User Object
// (
//     [id] => 1
//     [username] => aaa
//     [password] => aaa
//     [salt] => aaa
// )

rowCount() 返回查询结果数量

要获得查询的结果集行数就需要我们的 rowCount() 方法了。数据库中不管是查询还是增、删、改操作,都会返回语句执行结果,也就是受影响的行数。这些信息都是通过 rowCount() 这个方法获得的。

查询语句返回行数

需要注意的是,在查询语句中,有些数据是可能返回此语句的行数的。但这种方式不能保证对所有数据有效,且对可移植的应用更不要依赖这种方式。我们如果需要知道当前查询结果的数量,还是通过遍历 fetch() 或者通过 count(fetchAll()) 来根据真实查询到的结果集数量确定这一次查询的真实行数。

其实它就像是 PDO 对象的 exec() 方法所返回的数据。在不使用预处理语句的情况下,直接使用 PDO 的 exec() 方法执行 SQL 语句后,返回的也是语句执行后受影响的行数。

$stmt = $pdo->prepare("select * from zyblog_test_user");
$stmt->execute();
$rowCount = $stmt->rowCount();
echo $rowCount, PHP_EOL;
// 41

增、删、改语句返回受影响的行数

$stmt = $pdo->prepare("insert into zyblog_test_user(username, password, salt) values(?, ?, ?)");
$stmt->execute(['kkk','666','k6']);
$rowCount = $stmt->rowCount();
echo $rowCount, PHP_EOL; // 1
$id = $pdo->lastInsertId();
echo $rowCount, PHP_EOL; // 1

$stmt = $pdo->prepare("update zyblog_test_user set username=? where username = ?");
$stmt->execute(['ccc','cccc']);
$rowCount = $stmt->rowCount();
echo $rowCount, PHP_EOL; // 25

$stmt = $pdo->prepare("update zyblog_test_user set username=? where username = ?");
$stmt->execute(['ccc','cccc']);
$rowCount = $stmt->rowCount();
echo $rowCount, PHP_EOL; // 0

$stmt = $pdo->prepare("delete from zyblog_test_user where username = ?");
$stmt->execute(['ddd']);
$rowCount = $stmt->rowCount();
echo $rowCount, PHP_EOL; // 11

$stmt = $pdo->prepare("delete from zyblog_test_user where username = ?");
$stmt->execute(['ddd']);
$rowCount = $stmt->rowCount();
echo $rowCount, PHP_EOL; // 0

更新和删除操作在数据不存在、没有更新、没有删除的情况下都返回的是 0 。这一点我们也在 PDO 相关的第一篇文章中就说过了,对于业务来说,这种更新或删除到底算是成功还是失败呢?还是大家根据自己的实际业务情况来确定吧!

总结

关于 PDO 和 PDOStatement 相关的内容就学习到这里了。我们完整地梳理了一遍它们两个所有的方法,也都进行了相关的测试。大家在日常使用中可能接触到的并不多,框架都已经为我们封装好了。不过对于学习来说,平常的小测试、小调试完全可以自己手写来加深记忆和理解。在深入理解了这些扩展类的使用方法后,反过来又能帮助我们更加的清楚框架是如何去封装它们的。总之,学习就是不断的从高层到底层,再从底层返回高层,循环往复,才能更加的得心应手。

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202009/source/PHP%E4%B8%AD%E7%9A%84PDO%E6%93%8D%E4%BD%9C%E5%AD%A6%E4%B9%A0%EF%BC%88%E5%9B%9B%EF%BC%89%E6%9F%A5%E8%AF%A2%E7%BB%93%E6%9E%84%E9%9B%86.php

推荐学习:php视频教程

以上是三分鐘帶你了解PHP中的查詢結構集的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:segmentfault。如有侵權,請聯絡admin@php.cn刪除
酸與基本數據庫:差異和何時使用。酸與基本數據庫:差異和何時使用。Mar 26, 2025 pm 04:19 PM

本文比較了酸和基本數據庫模型,詳細介紹了它們的特徵和適當的用例。酸優先確定數據完整性和一致性,適合財務和電子商務應用程序,而基礎則側重於可用性和

PHP安全文件上傳:防止與文件相關的漏洞。PHP安全文件上傳:防止與文件相關的漏洞。Mar 26, 2025 pm 04:18 PM

本文討論了確保PHP文件上傳的確保,以防止諸如代碼注入之類的漏洞。它專注於文件類型驗證,安全存儲和錯誤處理以增強應用程序安全性。

PHP輸入驗證:最佳實踐。PHP輸入驗證:最佳實踐。Mar 26, 2025 pm 04:17 PM

文章討論了PHP輸入驗證以增強安全性的最佳實踐,重點是使用內置功能,白名單方法和服務器端驗證等技術。

PHP API率限制:實施策略。PHP API率限制:實施策略。Mar 26, 2025 pm 04:16 PM

本文討論了在PHP中實施API速率限制的策略,包括諸如令牌桶和漏水桶等算法,以及使用Symfony/Rate-limimiter之類的庫。它還涵蓋監視,動態調整速率限制和手

php密碼哈希:password_hash和password_verify。php密碼哈希:password_hash和password_verify。Mar 26, 2025 pm 04:15 PM

本文討論了使用password_hash和pyspasswify在PHP中使用密碼的好處。主要論點是,這些功能通過自動鹽,強大的哈希算法和SECH來增強密碼保護

OWASP前10 php:描述並減輕常見漏洞。OWASP前10 php:描述並減輕常見漏洞。Mar 26, 2025 pm 04:13 PM

本文討論了OWASP在PHP和緩解策略中的十大漏洞。關鍵問題包括注射,驗證損壞和XSS,並提供用於監視和保護PHP應用程序的推薦工具。

PHP XSS預防:如何預防XSS。PHP XSS預防:如何預防XSS。Mar 26, 2025 pm 04:12 PM

本文討論了防止PHP中XSS攻擊的策略,專注於輸入消毒,輸出編碼以及使用安全增強的庫和框架。

PHP接口與抽像類:何時使用。PHP接口與抽像類:何時使用。Mar 26, 2025 pm 04:11 PM

本文討論了PHP中接口和抽像類的使用,重點是何時使用。界面定義了無實施的合同,適用於無關類和多重繼承。摘要類提供常見功能

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)