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

深入 PHP 迭代器內部執行流程:手寫 Iterator 實現與 foreach 協作機制圖解

     編輯:PHP 相關知識

PHP foreach 能遍歷數組、對象、生成器,核心依賴 Iterator / IteratorAggregate / Traversable 接口。本文通過手寫 Iterator 實現,配合 var_dump(__METHOD__) 追蹤,完整還原迭代器內部調用時序,揭示 rewind → valid → current → key → next 循環機制。

標準 Iterator 接口

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 協作流程圖

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

移向下一個元素: 
當前元素: 
檢查有效性: 
// 結束

進階:IteratorAggregate 與生成器

  • IteratorAggregate:只需實現 getIterator(): Traversable,返回內部迭代器,適合包裝現有數組/對象。
  • 生成器 yield:自動實現 Iterator,無狀態、內存高效、語法極簡:
function gen() { yield 1; yield 2; yield 3; }
foreach (gen() as $v) { echo $v; } // 內部自動處理 rewind/valid/current/key/next

最佳實踐建議

  1. 優先使用生成器:簡單序列、大數據流、懶加載場景。
  2. 複雜狀態用 Iterator:需雙向遍歷、隨機訪問、外部資源游標(文件、數據庫、API 分頁)。
  3. 避免在 valid() 中調用 current():示例中為演示,實際應獨立邏輯,防止副作用。
  4. 實現 Countable:配合 count($iterator) 使用。
  5. 實現 ArrayAccess:支持 $iterator[0] 隨機訪問。
  6. 異常處理:next()、current() 遇無效位置拋出 OutOfBoundsException。

SPL 內置迭代器速查

迭代器用途
ArrayIterator數組對象化遍歷
DirectoryIterator目錄掃描
RecursiveDirectoryIterator遞歸目錄掃描
FilterIterator過濾包裝
LimitIterator切片/分頁
CachingIterator緩存前瞻
IteratorIterator任意 Traversable 轉 Iterator

掌握迭代器內部流程,讓你能精準控制遍歷行為、優化內存佔用、構建優雅的領域模型。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved