PHP 陣列內部維護一個「指標」指向當前元素。掌握指標操作函數,能高效實作迭代、倒序、特定位置存取等邏輯,尤其在處理大型陣列、避免複製、實作自定義迭代器時極具價值。本文系統整理所有指標函數、參數、回傳值、常見陷阱與實戰範例。
| 函數 | 原型 | 動作 | 回傳值 | 指標移動 |
|---|---|---|---|---|
current | current(array|object $array): mixed | 取得當前元素值 | 當前值 / false (指標超出範圍) | 否 |
next | next(array|object $array): mixed | 指標前進一格,取得下一個值 | 下一個值 / false (已是最後) | 是 (+1) |
prev | prev(array|object $array): mixed | 指標後退一格,取得上一個值 | 上一個值 / false (已是第一個) | 是 (-1) |
end | end(array|object $array): mixed | 指標移至最後一個元素 | 最後值 / false (空陣列) | 是 (至末尾) |
reset | reset(array|object $array): mixed | 指標重置至第一個元素 | 第一個值 / false (空陣列) | 是 (至開頭) |
each | each(array|object $array): array|false | 取得當前鍵值對,指標前進 | [key, value, 0=key, 1=value] / false | 是 (+1) |
key | key(array|object $array): mixed | 取得當前元素鍵名 | 鍵名 (int/string) / null (指標超出) | 否 |
<?php
$transport = ['foot', 'bike', 'car', 'plane'];
$mode = current($transport); // 'foot' (指標在 0)
$mode = next($transport); // 'bike' (指標移至 1)
$mode = next($transport); // 'car' (指標移至 2)
$mode = prev($transport); // 'bike' (指標退回 1)
$mode = end($transport); // 'plane' (指標跳至 3)
$mode = reset($transport); // 'foot' (指標回到 0)
// each() 回傳鍵值對陣列
reset($transport);
while (($pair = each($transport)) !== false) {
// $pair = [1 => 'foot', 'value' => 'foot', 0 => 0, 'key' => 0]
echo "Key: {$pair['key']}, Value: {$pair['value']}\n";
}
// 輸出:
// Key: 0, Value: foot
// Key: 1, Value: bike
// Key: 2, Value: car
// Key: 3, Value: plane
// 迴圈結束後指標在結尾 (false 位置)
?>
current(), next(), prev(), end(), reset() 回傳元素值。若元素值為 false, 0, '', null, [] 等 **falsy 值**,直接用於 `while` 判斷會誤以為結束。
// ❌ 錯誤:元素為 0 或 false 會中斷
while ($val = current($arr)) { next($arr); }
// ✅ 正確:用 key() !== null 判斷指標有效性
reset($arr);
while (key($arr) !== null) {
$val = current($arr);
// 處理 $val
next($arr);
}
// ✅ 更佳:foreach (不影響內部指標,PHP 7+ 複製陣列迭代)
foreach ($arr as $key => $val) { /* ... */ }
請勿在新代碼使用 `each()`**。改用 `foreach`、`ArrayIterator` 或手動 `key()`/`current()`/`next()` 組合。
所有指標函數參數為傳址呼叫 (內部修改指標位置),必須傳入**變數**,不可直接傳入陣列字面值或函數回傳陣列。
// ❌ 錯誤
current([1,2,3]); // Fatal error: Only variables can be passed by reference
// ✅ 正確
$arr = [1,2,3];
current($arr);
若物件實作 `Traversable` (如 `ArrayIterator`),指標函數也適用。但通常直接 `foreach` 更清晰。
<?php
function getAdjacentItems(array $items, int $currentIndex, int $window = 1): array
{
// 建立索引陣列 (保證連續數字鍵)
$indexed = array_values($items);
$count = count($indexed);
if ($currentIndex < 0 || $currentIndex >= $count) return [];
$result = ['current' => $indexed[$currentIndex]];
// 前一筆
if ($currentIndex - $window >= 0) {
$result['prev'] = $indexed[$currentIndex - $window];
}
// 後一筆
if ($currentIndex + $window < $count) {
$result['next'] = $indexed[$currentIndex + $window];
}
return $result;
}
// 使用
$articles = [/* ... 文章陣列 ... */];
$currentId = $_GET['id'] ?? 0;
$currentIndex = array_search($currentId, array_column($articles, 'id'));
$nav = getAdjacentItems($articles, $currentIndex);
<?php
function arrayPage(array &$array, int $page, int $perPage): array
{
$total = count($array);
$offset = ($page - 1) * $perPage;
if ($offset >= $total) return [];
// 利用指標跳轉 (僅適用數字索引陣列)
// 實務上 array_slice 較簡潔且不修改原陣列指標
return array_slice($array, $offset, $perPage, true); // true 保留鍵名
}
<?php
$arr = ['a', 'b', 'c'];
$ref = &$arr[1]; // 取得第二個元素的引用
next($arr); // 指標移至 'b'
var_dump(current($arr)); // 'b'
// 修改引用會影響原陣列
$ref = 'B_MODIFIED';
var_dump(current($arr)); // 'B_MODIFIED' (指標所指元素已被修改)
var_dump($arr[1]); // 'B_MODIFIED'
面向物件、可重用、支援多種迭代模式:
<?php
class ArticleCollection implements IteratorAggregate
{
private array $articles = [];
public function add(Article $article): void { $this->articles[] = $article; }
public function getIterator(): Traversable
{
return new ArrayIterator($this->articles);
}
// 可加入 getPrev(), getNext(), seek() 等自定義方法
}