PHP foreach 能遍歷數組、對象、生成器,核心依賴 Iterator / IteratorAggregate / Traversable 接口。本文通過手寫 Iterator 實現,配合 var_dump(__METHOD__) 追蹤,完整還原迭代器內部調用時序,揭示 rewind → valid → current → key → next 循環機制。
interface Iterator extends Traversable {
public function rewind(): void; // 重置指針到第一個元素
public function current(): mixed; // 返回當前元素值
public function key(): mixed; // 返回當前元素鍵
public function next(): void; // 移動指針到下一個元素
public function valid(): bool; // 判斷當前位置是否有效
}
<?php
class myIterator implements Iterator {
private $position = 0;
private $array = ["first_element", "second_element", "last_element"];
public function __construct() { $this->position = 0; }
public function rewind() { var_dump(__METHOD__); $this->position = 0; }
public function current() { var_dump(__METHOD__); return $this->array[$this->position]; }
public function key() { var_dump(__METHOD__); return $this->position; }
public function next() { var_dump(__METHOD__); ++$this->position; }
public function valid() { var_dump(__METHOD__); return isset($this->array[$this->position]); }
}
$it = new myIterator;
foreach ($it as $key => $value) {
echo '輸出鍵值:';
var_dump($key, $value);
echo "\n";
}
string(18) "myIterator::rewind" // 1. 進入 foreach 先調用 rewind string(17) "myIterator::valid" // 2. 檢查有效性 string(19) "myIterator::current" // 3. 獲取當前值 string(15) "myIterator::key" // 4. 獲取當前鍵 // --- 循環體開始 --- 輸出鍵值:int(0) string(13) "first_element" string(16) "myIterator::next" // 5. 循環體結束,移動指針 string(17) "myIterator::valid" // 6. 檢查下一個有效性 string(19) "myIterator::current" // 7. 獲取值 string(15) "myIterator::key" // 8. 獲取鍵 // --- 循環體 --- 輸出鍵值:int(1) string(14) "second_element" string(16) "myIterator::next" string(17) "myIterator::valid" string(19) "myIterator::current" string(15) "myIterator::key" 輸出鍵值:int(2) string(12) "last_element" string(16) "myIterator::next" // 移動到越界位置 string(17) "myIterator::valid" // 返回 false // foreach 結束,不再調用 current/key
foreach ($iterator as $key => $value) {
// 等價於:
$iterator->rewind();
while ($iterator->valid()) {
$key = $iterator->key();
$value = $iterator->current();
// --- 循環體代碼 ---
$iterator->next();
}
}
<?php
class MyIterator implements Iterator {
private $var = [];
public function __construct(array $array) { $this->var = $array; }
public function rewind() { echo "倒回第一個元素\n"; reset($this->var); }
public function current() { $v = current($this->var); echo "當前元素: $v\n"; return $v; }
public function key() { $k = key($this->var); echo "當前元素的鍵: $k\n"; return $k; }
public function next() { $v = next($this->var); echo "移向下一個元素: $v\n"; return $v; }
public function valid() { $v = $this->current() !== false; echo "檢查有效性: " . ($v ? 'true' : 'false') . "\n"; return $v; }
}
$values = [1,2,3];
$it = new MyIterator($values);
foreach ($it as $k => $v) {
print "此時鍵值對 -- key $k: value $v\n\n";
}
倒回第一個元素 當前元素: 1 檢查有效性: 1 當前元素: 1 當前元素的鍵: 0 此時鍵值對 -- key 0: value 1 移向下一個元素: 2 當前元素: 2 檢查有效性: 1 當前元素: 2 當前元素的鍵: 1 此時鍵值對 -- key 1: value 2 移向下一個元素: 3 當前元素: 3 檢查有效性: 1 當前元素: 3 當前元素的鍵: 2 此時鍵值對 -- key 2: value 3 移向下一個元素: 當前元素: 檢查有效性: // 結束
getIterator(): Traversable,返回內部迭代器,適合包裝現有數組/對象。yield:自動實現 Iterator,無狀態、內存高效、語法極簡:function gen() { yield 1; yield 2; yield 3; }
foreach (gen() as $v) { echo $v; } // 內部自動處理 rewind/valid/current/key/next
count($iterator) 使用。$iterator[0] 隨機訪問。next()、current() 遇無效位置拋出 OutOfBoundsException。| 迭代器 | 用途 |
|---|---|
ArrayIterator | 數組對象化遍歷 |
DirectoryIterator | 目錄掃描 |
RecursiveDirectoryIterator | 遞歸目錄掃描 |
FilterIterator | 過濾包裝 |
LimitIterator | 切片/分頁 |
CachingIterator | 緩存前瞻 |
IteratorIterator | 任意 Traversable 轉 Iterator |
掌握迭代器內部流程,讓你能精準控制遍歷行為、優化內存佔用、構建優雅的領域模型。