PHP中的數(shù)組分頁實(shí)現(xiàn)(非數(shù)據(jù)庫)

在日常開發(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è) \data 就是從數(shù)據(jù)庫中取出的全部數(shù)據(jù),或者就是我們寫死在 PHP 代碼中的數(shù)據(jù)灌侣。然后我們設(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 ,也就是只獲取 3 條數(shù)據(jù)湿滓。最后滴须,我們計(jì)算了一下偏移量,也就是類似于 MySQL 的 LIMIT 中的那個參數(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)前頁 currentPage 和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://github.com/zhangyue0503/dev-blog/blob/master/php/202008/source/PHP%E4%B8%AD%E7%9A%84%E6%95%B0%E7%BB%84%E5%88%86%E9%A1%B5%E5%AE%9E%E7%8E%B0%EF%BC%88%E9%9D%9E%E6%95%B0%E6%8D%AE%E5%BA%93%EF%BC%89.php

參考文檔:

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)理】

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末费变,一起剝皮案震驚了整個濱河市摧扇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌挚歧,老刑警劉巖扛稽,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異滑负,居然都是意外死亡在张,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門矮慕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瞧掺,“玉大人,你說我怎么就攤上這事凡傅”俦罚” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵夏跷,是天一觀的道長哼转。 經(jīng)常有香客問我,道長槽华,這世上最難降的妖魔是什么壹蔓? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮猫态,結(jié)果婚禮上佣蓉,老公的妹妹穿的比我還像新娘披摄。我一直安慰自己,他們只是感情好勇凭,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布疚膊。 她就那樣靜靜地躺著,像睡著了一般虾标。 火紅的嫁衣襯著肌膚如雪寓盗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天璧函,我揣著相機(jī)與錄音傀蚌,去河邊找鬼。 笑死蘸吓,一個胖子當(dāng)著我的面吹牛善炫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播库继,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼箩艺,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了制跟?” 一聲冷哼從身側(cè)響起舅桩,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎雨膨,沒想到半個月后擂涛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡聊记,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年撒妈,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片排监。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡狰右,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出舆床,到底是詐尸還是另有隱情棋蚌,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布挨队,位于F島的核電站谷暮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏盛垦。R本人自食惡果不足惜湿弦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望腾夯。 院中可真熱鬧颊埃,春花似錦蔬充、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至肥败,卻和暖如春趾浅,著一層夾襖步出監(jiān)牢的瞬間愕提,已是汗流浹背馒稍。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留浅侨,地道東北人纽谒。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像如输,于是被迫代替她去往敵國和親鼓黔。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容