一、什麼是Iterable接口
Iterable接口是PHP 7.1中新增加的一個接口,用來表示一個類是否能夠被迭代。一個類只要實現了Iterator或者IteratorAggregate接口,就可以被foreach迭代。
實現Iterator接口需要實現以下4個方法:
class MyIterator implements Iterator { private $items = []; private $currentIndex = 0; public function __construct(array $items) { $this->items = $items; } public function rewind() { $this->currentIndex = 0; } public function current() { return $this->items[$this->currentIndex]; } public function key() { return $this->currentIndex; } public function next() { $this->currentIndex++; } public function valid() { return isset($this->items[$this->currentIndex]); } }
實現IteratorAggregate接口需要實現一個getIterator方法,返回一個實現了Iterator接口的對象,例如:
class MyIterable implements IteratorAggregate { private $items = []; public function __construct(array $items) { $this->items = $items; } public function getIterator() { return new MyIterator($this->items); } }
二、Iterable接口的作用
Iterable接口的作用是可以讓我們自定義的數據結構通過foreach語法進行遍歷。
例如下面這個例子,我們可以實現一個自定義的鏈表數據結構,並使用foreach語法遍歷鏈表:
class ListNode { public $val = 0; public $next = null; public function __construct($val) { $this->val = $val; } } class LinkedList implements IteratorAggregate { public $head = null; public $tail = null; public $count = 0; public function add($node) { if ($this->head == null) { $this->head = $node; $this->tail = $node; } else { $this->tail->next = $node; $this->tail = $node; } $this->count++; } public function getIterator() { $node = $this->head; while ($node) { yield $node; $node = $node->next; } } } $list = new LinkedList(); $list->add(new ListNode(1)); $list->add(new ListNode(2)); $list->add(new ListNode(3)); foreach ($list as $node) { echo $node->val . " "; } // output: 1 2 3
通過實現IteratorAggregate接口,並使getIterator方法返回一個生成器,就可以實現在自定義的鏈表數據結構上使用foreach語法遍歷。
三、Iterable接口的注意事項
在實現IteratorAggregate接口時,如果返回的Iterator沒有實現Rewindable接口,那麼鍵為0的元素不會被遍歷。
例如下面的例子:
class MyIterator implements Iterator { private $count = 3; private $currentIndex = 0; public function rewind() { $this->currentIndex = 0; } public function current() { return $this->currentIndex; } public function key() { return $this->currentIndex; } public function next() { $this->currentIndex++; $this->count--; } public function valid() { return $this->count > 0; } } class MyIterable implements IteratorAggregate { public function getIterator() { return new MyIterator(); } } $iterable = new MyIterable(); foreach ($iterable as $key => $value) { echo "{$key} => {$value}\n"; } // 輸出為1 => 1, 2 => 2
在這個例子中,$key為0的元素並沒有被遍歷,這是因為MyIterator沒有實現Rewindable接口。如果要使所有元素都被遍歷,需要在MyIterator中實現rewind方法。
四、Iterable接口的擴展
除了Iterator和IteratorAggregate接口,PHP還提供了Generator接口,它讓我們可以在調用生成器函數時,使用foreach語法一樣地對生成器提供迭代器。同時,Generator方法可以實現中斷和恢復執行的能力,可以用於處理大量數據進行分批次處理。
以數據分塊為例,下面是處理csv文件時,使用Generator實現文件分塊處理的一個例子:
function readData($filename, $blockSize) { if (!$handle = fopen($filename, 'r')) { throw new InvalidArgumentException("Cannot open file ($filename)"); } $lineCount = 0; $block = ""; while (!feof($handle)) { $line = fgets($handle); $block .= $line; $lineCount++; if ($lineCount >= $blockSize) { $lineCount = 0; yield $block; $block = ""; } } if (!empty($block)) { yield $block; } fclose($handle); } $filename = "large.csv"; $blockSize = 1000; foreach (readData($filename, $blockSize) as $block) { // process each block of data }
此處是一個基於Generator實現的分塊處理csv文件的例子,可以使用foreach語法一樣地對生成器提供迭代器,同時也支持生成器的中斷和恢復執行的能力,可以用於處理大量數據進行分批次處理。
五、總結
Iterable接口是PHP 7.1新增的一個接口,使用Iterable接口可以實現自定義的數據結構在遍歷時使用foreach語法。通過實現Iterator或IteratorAggregate接口,並使getIterator方法返回一個可迭代的對象,就可以在自定義的數據結構上使用foreach語法。
除了Iterator和IteratorAggregate接口,PHP還提供了Generator接口,可以在調用生成器函數時,使用foreach語法一樣地對生成器提供迭代器。Generator方法可以實現中斷和恢復執行的能力,可以用於處理大量數據進行分塊處理。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/200971.html