首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 二維陣列切片技巧:自訂 array_slice 支援多維陣列分頁

     編輯:PHP 相關知識

array_slice() 的限制與二維陣列挑戰

PHP 內建 array_slice() 僅支援一維陣列,直接用於二維陣列會將子陣列視為單一元素切割,無法達到「取前 N 筆記錄」或「取第 M 欄位前 N 個值」的需求。本文提供通用解決方案。

一維陣列切片基礎回顧

'b', 2=>'c'] 保留鍵名

二維陣列常見切片需求

需求 1:取前 N 筆記錄(分頁常用)

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 直接可用

需求 2:取指定欄位的前 N 個值

需求 3:複雜結構 — 每筆記錄長度不一,取總元素數前 N 個

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. 直接用 array_slice($2d_arr, 0, 5) 取的是前 5 筆記錄,非前 5 個子元素
  2. array_column($data, 'key') 後再 slice 只適用於固定欄位,不適用於不定長度子陣列
  3. offset 超過總數 回傳空陣列,需處理邊界
  4. 記憶體:array_merge 重建陣列,大量資料考慮生成器 yield 逐個產出
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
資料量建議方案
總元素 < 1萬上述 PHP 函式足夠
總元素 1萬-10萬預先扁平化建立索引陣列,或用資料庫
總元素 > 10萬資料庫分頁 (LIMIT/OFFSET) 或游標分頁