文章清單原本用 101、205、309 當鍵名,切出第二筆後卻看到鍵名變成 0。若你用了 array_slice(),這是預設的數字鍵名重編行為,不表示資料庫把文章 ID 改掉了。當後面的程式拿鍵名組文章連結時,就可能連到錯誤的位置。
先分清資料用途:這個陣列是「ID 對標題」的對照表,還是只要順序的普通列表。前者通常要保留鍵名;後者從 0 開始編號可能正是你要的結果。以下用三筆字串示例,不讀寫正式文章或資料庫。
預設會保留值,卻把整數鍵名重編
$titlesById = [
101 => 'A',
205 => 'B',
309 => 'C',
];
$page = array_slice($titlesById, 1, 1);
var_export($page);
// [0 => 'B']
第一個 1 是偏移量,表示略過第一筆;第二個 1 是最多取一筆。值 B 留下來了,但原來的整數鍵名 205 被重編為 0。因此只檢查標題有沒有取對,還不足以確認 ID 對照表完整。
array_slice() 回傳切片,不會直接刪除原陣列中的項目。上例的 $titlesById 仍有原來三筆;不過,如果你把切片結果重新指定回同一個變數,之後看到的自然就是切片後的內容。
用第四個參數保留文章 ID
後續程式需要以鍵名當文章 ID 時,把第四個參數 preserve_keys 設成 true:
$page = array_slice($titlesById, 1, 1, true);
var_export($page);
// [205 => 'B']
foreach ($page as $postId => $title) {
echo $postId . ': ' . $title . PHP_EOL;
}
// 205: B
這個設定保留的是原鍵名,不會另造一個 ID,也不會替你核對資料庫裡有沒有那篇文章。產生連結或送出更新請求時,仍要依實際資料與權限處理;不要把「鍵名保住了」當成整個更新流程已驗證。
偏移量是第幾筆,不是鍵名多少
即使設定 true,第二個參數依然是位置,不會改成按 ID 搜尋。若你把 205 當成偏移量,這個只有三筆的陣列就取不到資料:
$wrong = array_slice($titlesById, 205, 1, true);
var_export($wrong);
// []
$right = array_slice($titlesById, 1, 1, true);
var_export($right);
// [205 => 'B']
要取 ID 205 的值,可以按你的資料規則先檢查鍵名是否存在,再用該鍵名存取。要按頁數取資料,則先確定排序、每頁筆數與頁碼,再算位置偏移量。保留鍵名不會自動排序,也不會把 PHP 記憶體中的切片變成資料庫分頁。
字串鍵名和普通列表要分開看
PHP 手冊指出,真正的字串鍵名不受這個參數影響,切片時本來就會保留。例如下列 slug 對照表,不加 true 仍會留下 guide:
$bySlug = ['home' => 'A', 'guide' => 'B'];
var_export(array_slice($bySlug, 1, 1));
// ['guide' => 'B']
不要只看寫法有沒有引號就判斷鍵名型別;部分數字字串在 PHP 建立陣列時會轉成整數鍵名。若來源混有這類資料,先檢查實際鍵名,而不是假設所有來自表單的字串都會一直保留字串型別。
如果你確實需要從 0 開始的普通列表,可以明確使用 array_values($page) 取值並重新編號。這也表示鍵名承載的 ID 會消失;API 若要同時提供順序列表與 ID,通常應把 ID 放在每筆資料的明確欄位裡,不只藏在外層鍵名。
修改既有切頁程式時,用同一組資料對照切片前後的鍵名、值與原陣列。確認連結使用的 ID 仍是原值,再檢查空頁的處理。只把 false 改成 true,卻沒核對下游是否原本依賴連續索引,也可能造成另一種讀取錯誤。
