| 介面 | 繼承關係 | 核心用途 |
|---|---|---|
| Countable | 獨立 | 支援 count() 計數 |
| OuterIterator | extends Iterator | 包裝/修飾其他迭代器 |
| RecursiveIterator | extends Iterator | 遞迴遍歷多層結構 |
| SeekableIterator | extends Iterator | 支援 seek() 隨機存取 |
| SplObserver | 獨立 | 觀察者模式:觀察者角色 |
| SplSubject | 獨立 | 觀察者模式:被觀察者角色 |
<?php
class MyCollection implements Countable {
private array $data = [];
private int $count = 0;
public function add(mixed $item): void {
$this->data[] = $item;
}
public function count(): int {
return ++$this->count; // 示例:每次 count() 遞增
}
}
$col = new MyCollection();
$col->add('a');
$col->add('b');
echo count($col); // 3 (呼叫 count() 兩次 + 初始)
echo count($col); // 4
注意:count() 第二參數 mode 不影響行為。
<?php
class MyOuterIterator extends IteratorIterator {
public function current(): mixed {
return parent::current() . 'TEST'; // 修飾每個元素
}
}
$arr = ['b', 'a', 'c'];
foreach (new MyOuterIterator(new ArrayIterator($arr)) as $key => $value) {
echo "$key => $value\n";
}
/* 輸出:
0 => bTEST
1 => aTEST
2 => cTEST
*/
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', 'pass');
$pdo->exec('SET NAMES utf8mb4');
$stmt = $pdo->query('SELECT * FROM users LIMIT 10');
$iterator = new IteratorIterator($stmt); // PDOStatement 實現 Traversable
$users = iterator_to_array($iterator);
print_r($users);
新增兩方法:
hasChildren():當前元素是否有子迭代器getChildren():取得子迭代器<?php
class MyRecursiveIterator implements RecursiveIterator {
private array $data;
private int $position = 0;
public function __construct(array $data) { $this->data = $data; }
public function valid(): bool { return isset($this->data[$this->position]); }
public function current(): mixed { return $this->data[$this->position]; }
public function key(): mixed { return $this->position; }
public function next(): void { $this->position++; }
public function rewind(): void { $this->position = 0; }
public function hasChildren(): bool {
return is_array($this->data[$this->position]);
}
public function getChildren(): RecursiveIterator {
return new self($this->data[$this->position]);
}
}
$data = [0, 1 => [10, 20], 2, 3 => [1, 2]];
$it = new MyRecursiveIterator($data);
foreach ($it as $key => $val) {
if ($it->hasChildren()) {
echo "$key has children:\n";
foreach ($it->getChildren() as $ck => $cv) {
echo " [$ck] => $cv\n";
}
} else {
echo "$val\n";
}
}
/* 輸出:
0
1 has children:
[0] => 10
[1] => 20
2
3 has children:
[0] => 1
[1] => 2
*/
核心方法:seek(int $position) 跳轉到指定位置,越界拋出 OutOfBoundsException。
<?php
class MySeekableIterator implements SeekableIterator {
private int $position = 0;
private array $data = ['first', 'second', 'third', 'fourth'];
public function seek(int $position): void {
if (!isset($this->data[$position])) {
throw new OutOfBoundsException("Invalid seek position ($position)");
}
$this->position = $position;
}
public function rewind(): void { $this->position = 0; }
public function current(): mixed { return $this->data[$this->position]; }
public function key(): mixed { return $this->position; }
public function next(): void { $this->position++; }
public function valid(): bool { return isset($this->data[$this->position]); }
}
try {
$it = new MySeekableIterator();
echo $it->current() . "\n"; // first
$it->seek(2);
echo $it->current() . "\n"; // third
$it->seek(1);
echo $it->current() . "\n"; // second
$it->seek(10); // 拋出例外
} catch (OutOfBoundsException $e) {
echo "錯誤: " . $e->getMessage() . "\n"; // Invalid seek position (10)
}
<?php
// 被觀察者
class NewsLetter implements SplSubject {
private array $observers = [];
private string $latestNews = '';
public function attach(SplObserver $observer): void {
$this->observers[] = $observer;
}
public function detach(SplObserver $observer): void {
$key = array_search($observer, $this->observers, true);
if ($key !== false) unset($this->observers[$key]);
}
public function notify(): void {
foreach ($this->observers as $obs) {
$obs->update($this);
}
}
public function setNews(string $news): void {
$this->latestNews = $news;
$this->notify();
}
public function getNews(): string { return $this->latestNews; }
}
// 觀察者
class EmailSubscriber implements SplObserver {
public function update(SplSubject $subject): void {
echo "Email 發送: " . $subject->getNews() . "\n";
}
}
class SMSSubscriber implements SplObserver {
public function update(SplSubject $subject): void {
echo "SMS 發送: " . $subject->getNews() . "\n";
}
}
// 使用
$news = new NewsLetter();
$news->attach(new EmailSubscriber());
$news->attach(new SMSSubscriber());
$news->setNews('PHP 8.3 釋出!');
/* 輸出:
Email 發送: PHP 8.3 釋出!
SMS 發送: PHP 8.3 釋出!
*/
count($obj) → 實現 CountableRecursiveIteratorIterator 使用