在日常開發(fā)的業(yè)務(wù)環(huán)境中墓怀,我們一般都會使用 MySQL 語句來實(shí)現(xiàn)分頁的功能。但是吱涉,往往也有些數(shù)據(jù)并不多刹泄,或者只是獲取 PHP 中定義的一些數(shù)組數(shù)據(jù)時需要分頁的功能外里。這時怎爵,我們其實(shí)不需要每次都去查詢數(shù)據(jù)庫,可以在一次查詢中把所有的數(shù)據(jù)取出來盅蝗,然后在 PHP 的代碼層面進(jìn)行分頁功能的實(shí)現(xiàn)鳖链。今天,我們就來學(xué)習(xí)一下可以實(shí)現(xiàn)這個能力的一些函數(shù)技巧。
首先芙委,我們還是準(zhǔn)備好測試數(shù)據(jù)逞敷。
$data = [
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
];
// $p = $_GET['p'];
$p = 2;
$currentPage = $p <= 1 ? 0 : $p - 1;
$pageSize = 3;
$offset = $currentPage * $pageSize;
假設(shè) \p 為接收到的請求參數(shù)推捐,當(dāng)前訪問的是第二頁。$currentPage 是用于查詢偏移量的修正侧啼,在代碼開發(fā)的世界中牛柒,下標(biāo)索引都是從0開始的,所以我們需要對接收到的參數(shù)進(jìn)行減一的操作痊乾。當(dāng)然皮壁,你也可以設(shè)定前端傳遞的參數(shù)就是以 0 為第一頁的。這個就不多解釋了哪审,相信大家只要正式的學(xué)習(xí)或者參與過開發(fā)項(xiàng)目都會明白它的意思蛾魄。
然后我們定義了當(dāng)前頁面所顯示的信息條數(shù) pageSize 查詢幾條。這樣我們就可以獲得當(dāng)前頁面對應(yīng)的數(shù)據(jù)了而线。(貌似把分頁的原理都講了一下)
array_slice
第一個也是最基礎(chǔ)和最常見的分頁方式铭污,就是使用 array_slice() 函數(shù)來實(shí)現(xiàn)。它的作用是從數(shù)組中截取出一段內(nèi)容來并返回這段內(nèi)容的數(shù)組膀篮。
var_dump(array_slice($data, $offset, $pageSize));
// array(3) {
// [0]=>
// string(1) "D"
// [1]=>
// string(1) "E"
// [2]=>
// string(1) "F"
// }
array_slice() 函數(shù)需要三個參數(shù)嘹狞,第二個參數(shù)就是偏移量,第三個參數(shù)是查詢幾條數(shù)據(jù)誓竿。其中磅网,第三個參數(shù)是可選的,不填的話就會把當(dāng)前設(shè)定的偏移量之后的數(shù)據(jù)全部顯示出來筷屡。是不是和我們的 MySQL 查詢語句一模一樣涧偷。沒錯,他們本身就是類似的操作毙死。
array_chunk
array_chunk() 函數(shù)則是根據(jù)一個數(shù)值參數(shù)將一個數(shù)組進(jìn)行分組燎潮,也就是將數(shù)組分割成一段一段的子數(shù)組。我們就可以根據(jù)分割后的數(shù)組來獲取指定下標(biāo)的子數(shù)組內(nèi)容扼倘,這些內(nèi)容就是當(dāng)前的頁面需要展示的數(shù)據(jù)了确封。
$pages = array_chunk($data, $pageSize);
var_dump($pages);
// array(4) {
// [0]=>
// array(3) {
// [0]=>
// string(1) "A"
// [1]=>
// string(1) "B"
// [2]=>
// string(1) "C"
// }
// [1]=>
// array(3) {
// [0]=>
// string(1) "D"
// [1]=>
// string(1) "E"
// [2]=>
// string(1) "F"
// }
// [2]=>
// array(3) {
// [0]=>
// string(1) "G"
// [1]=>
// string(1) "H"
// [2]=>
// string(1) "I"
// }
// [3]=>
// array(2) {
// [0]=>
// string(1) "J"
// [1]=>
// string(1) "K"
// }
// }
var_dump($pages[$currentPage]);
// array(3) {
// [0]=>
// string(1) "A"
// [1]=>
// string(1) "B"
// [2]=>
// string(1) "C"
// }
這段代碼我們輸出了分割后的數(shù)組內(nèi)容,然后需要的是第二頁也就是下標(biāo)為 1 的數(shù)據(jù),直接通過分割后的數(shù)組就可以方便地獲取到所需要的內(nèi)容了爪喘。使用這個函數(shù)來做數(shù)組分頁的功能非常地簡單直觀颜曾,而且它不需要去計(jì)算偏移量,直接就是使用當(dāng)前頁 pageSize 就可以完成對于數(shù)據(jù)的分組了秉剑,非常推薦大家使用這個函數(shù)來進(jìn)行類似的操作泛豪。
LimitIterator
最后我們要學(xué)習(xí)到的是使用一個迭代器類來實(shí)現(xiàn)數(shù)組分頁的能力,這個使用的就比較少了侦鹏,估計(jì)都沒什么人知道候址,但其實(shí) LimitIterator 類在 PHP5.1 時就已經(jīng)提供了。它的作用是允許遍歷一個 Iterator 的限定子集的元素种柑。也就是說岗仑,如果我們的代碼中使用了迭代器模式,實(shí)現(xiàn)了迭代器接口聚请,那么這些迭代器類都可以使用這個類進(jìn)行分頁操作荠雕。
foreach (new LimitIterator(new ArrayIterator($data), $offset, $pageSize) as $d) {
var_dump($d);
}
// string(1) "D"
// string(1) "E"
// string(1) "F"
它需要的實(shí)例化構(gòu)造參數(shù)包含3個,第一個是一個迭代器對象驶赏,由于數(shù)組不是迭代器對象炸卑,所以我們使用 ArrayIterator 實(shí)例將我們的數(shù)組數(shù)據(jù)轉(zhuǎn)化為一個迭代器對象。后面兩個參數(shù)就是偏移量和數(shù)據(jù)數(shù)量了煤傍,這個和 array_slice() 函數(shù)是類似的盖文,不過不同的是,它的偏移量參數(shù)也是可以選的蚯姆。如果我們不給后面的可選參數(shù)的話五续,那么它將遍歷所有的數(shù)據(jù)。
foreach (new LimitIterator(new ArrayIterator($data)) as $d) {
var_dump($d);
}
// string(1) "A"
// string(1) "B"
// string(1) "C"
// string(1) "D"
// string(1) "E"
// string(1) "F"
// string(1) "G"
// string(1) "H"
// string(1) "I"
// string(1) "J"
// string(1) "K"
參數(shù)錯誤時的表現(xiàn)
接下來龄恋,我們看看如果參數(shù)錯誤疙驾,也就是偏移量或者所需的數(shù)據(jù)量大小有問題的話,這些操作將會有什么樣的表現(xiàn)郭毕。
var_dump(array_slice($data, $offset, 150));
// array(8) {
// [0]=>
// string(1) "D"
// [1]=>
// string(1) "E"
// [2]=>
// string(1) "F"
// [3]=>
// string(1) "G"
// [4]=>
// string(1) "H"
// [5]=>
// string(1) "I"
// [6]=>
// string(1) "J"
// [7]=>
// string(1) "K"
// }
var_dump(array_slice($data, 15, $pageSize));
// array(0) {
// }
array_slice() 函數(shù)對于偏移量錯誤的兼容就是展示一個空的數(shù)組它碎。而數(shù)據(jù)量超標(biāo)的話則會展示所有偏移量之后的數(shù)據(jù)。
var_dump($pages[15]);
// NULL
array_chunk() 對于下標(biāo)不存在的數(shù)據(jù)當(dāng)然就是返回一個 NULL 值啦显押。
foreach (new LimitIterator(new ArrayIterator($data), $offset, 150) as $d) {
var_dump($d);
}
// string(1) "D"
// string(1) "E"
// string(1) "F"
// string(1) "G"
// string(1) "H"
// string(1) "I"
// string(1) "J"
// string(1) "K"
foreach (new LimitIterator(new ArrayIterator($data), 15, $pageSize) as $d) {
var_dump($d);
}
// Fatal error: Uncaught OutOfBoundsException: Seek position 15 is out of range
LimitIterator 則是對于偏移量錯誤的數(shù)據(jù)直接返回錯誤異常信息了扳肛。這也是類模式處理的好處,有錯誤都會以異常的形式進(jìn)行返回乘碑,方便我們對異常進(jìn)行后續(xù)的處理挖息。
其它的測試大家還可以自行檢測,比如偏移是 0 或者是負(fù)數(shù)的情況蝉仇,數(shù)據(jù)量是 0 或者是負(fù)數(shù)的情況旋讹。這些我就不多寫了殖蚕,大家可以根據(jù)已有的知識先猜想一下結(jié)果會是什么樣的轿衔,然后再自己寫代碼驗(yàn)證一下結(jié)果是符合自己的預(yù)期沉迹,這樣學(xué)習(xí)的效果會非常棒哦!(在下方測試代碼鏈接中有測試害驹,結(jié)果里面是有坑的哦)
總結(jié)
一個功能使用了三種方式來實(shí)現(xiàn)鞭呕,這就是代碼的魅力。至于哪個好哪個壞我們不多做評價宛官,一切都是以業(yè)務(wù)為核心來進(jìn)行選取葫松。類似的功能雖說并不常見,但很多項(xiàng)目里都會遇到底洗,比如說后臺用戶組管理就會非常常見腋么,一般來說后臺用戶分組如果不是特別大型的 ERP 項(xiàng)目都不會很多,但有時候也會達(dá)到需要分頁的程度亥揖,這時候珊擂,我們就可以考慮考慮使用今天所學(xué)的知識來做咯!
測試代碼:
參考文檔:
https://www.php.net/manual/zh/function.array-slice.php
https://www.php.net/manual/zh/function.array-chunk.php
https://www.php.net/limititerator
各自媒體平臺均可搜索【硬核項(xiàng)目經(jīng)理】