PHP 內建 array_slice() 僅支援一維陣列,直接用於二維陣列會將子陣列視為單一元素切割,無法達到「取前 N 筆記錄」或「取第 M 欄位前 N 個值」的需求。本文提供通用解決方案。
'b', 2=>'c'] 保留鍵名
1, 'name'=>'A'],
['id'=>2, 'name'=>'B'],
['id'=>3, 'name'=>'C'],
['id'=>4, 'name'=>'D'],
['id'=>5, 'name'=>'E'],
];
// 目標:取前 3 筆
$page = array_slice($users, 0, 3);
// 正確!二維陣列每筆為一元素,array_slice 直接可用
1, 'photos'=>['a.jpg','b.jpg','c.jpg']], // 3 張
['id'=>2, 'photos'=>['d.jpg','e.jpg']], // 2 張
['id'=>3, 'photos'=>['f.jpg','g.jpg','h.jpg','i.jpg']], // 4 張
];
// 目標:扁平化取前 5 張照片路徑
// 結果應為:['a.jpg','b.jpg','c.jpg','d.jpg','e.jpg']
$row) {
if (!isset($row[$child_key]) || !is_array($row[$child_key])) {
continue;
}
$children = $row[$child_key];
$childCount = count($children);
// 尚未跳過足夠的 offset
if ($skipped + $childCount <= $offset) {
$skipped += $childCount;
continue;
}
// 計算在當前子陣列的起始位置
$start = max(0, $offset - $skipped);
$take = min($childCount - $start, $limit - $count);
if ($take > 0) {
$slice = array_slice($children, $start, $take);
$result = array_merge($result, $slice);
$count += count($slice);
}
if ($count >= $limit) break;
$skipped += $childCount;
}
return $result;
}
// 使用
$photos = array_slice_deep($albums, 'photos', 5);
// ['a.jpg','b.jpg','c.jpg','d.jpg','e.jpg']
// 分頁:第 2 頁,每頁 3 張
$page2 = array_slice_deep($albums, 'photos', 3, 3);
// ['d.jpg','e.jpg','f.jpg']
$row) {
if (!isset($row[$child_key]) || !is_array($row[$child_key])) {
continue;
}
$children = $row[$child_key];
$childCount = count($children);
if ($skipped + $childCount <= $offset) {
$skipped += $childCount;
continue;
}
$start = max(0, $offset - $skipped);
$take = min($childCount - $start, $limit - $count);
if ($take > 0) {
$newRow = $row;
$newRow[$child_key] = array_slice($children, $start, $take);
$result[$parentKey] = $newRow;
$count += $take;
}
if ($count >= $limit) break;
$skipped += $childCount;
}
return $result;
}
// 使用:保留相簿結構,只取前 5 張照片
$albumsPreview = array_slice_deep_preserve($albums, 'photos', 5);
/*
[
0 => ['id'=>1, 'photos'=>['a.jpg','b.jpg','c.jpg']],
1 => ['id'=>2, 'photos'=>['d.jpg','e.jpg']],
// 第 3 相簿被截斷,不包含在內
]
*/
data = $data; $this->childKey = $childKey; $this->perPage = $perPage; } public function getPage(int $page): array { $page = max(1, $page); $offset = ($page - 1) * $this->perPage; return array_slice_deep($this->data, $this->childKey, $this->perPage, $offset); } public function getPagePreserve(int $page): array { $page = max(1, $page); $offset = ($page - 1) * $this->perPage; return array_slice_deep_preserve($this->data, $this->childKey, $this->perPage, $offset); } public function totalItems(): int { $total = 0; foreach ($this->data as $row) { if (isset($row[$this->childKey]) && is_array($row[$this->childKey])) { $total += count($row[$this->childKey]); } } return $total; } public function totalPages(): int { return (int)ceil($this->totalItems() / $this->perPage); } } // 使用 $paginator = new ArrayPaginator($albums, 'photos', 3); echo "總照片: {$paginator->totalItems()}"; // 9 echo "總頁數: {$paginator->totalPages()}"; // 3 foreach (range(1, $paginator->totalPages()) as $page) { echo "第 $page 頁: "; print_r($paginator->getPage($page)); }
| 資料量 | 建議方案 |
|---|---|
| 總元素 < 1萬 | 上述 PHP 函式足夠 |
| 總元素 1萬-10萬 | 預先扁平化建立索引陣列,或用資料庫 |
| 總元素 > 10萬 | 資料庫分頁 (LIMIT/OFFSET) 或游標分頁 |