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

PHP SPL 標準庫介面深度解析:6 大核心介面實戰

     編輯:PHP 相關知識

SPL 6 大核心介面總覽

介面繼承關係核心用途
Countable獨立支援 count() 計數
OuterIteratorextends Iterator包裝/修飾其他迭代器
RecursiveIteratorextends Iterator遞迴遍歷多層結構
SeekableIteratorextends Iterator支援 seek() 隨機存取
SplObserver獨立觀察者模式:觀察者角色
SplSubject獨立觀察者模式:被觀察者角色

1. Countable:讓物件支援 count()

<?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 不影響行為。

2. OuterIterator:包裝與修飾迭代器

<?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
*/

實戰:PDOStatement 直接轉陣列

<?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);

3. RecursiveIterator:多層結構遞迴遍歷

新增兩方法:

  • 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
*/

4. SeekableIterator:隨機存取迭代器

核心方法: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)
}

5. SplObserver & SplSubject:觀察者模式標準實現

<?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) → 實現 Countable
  • 需要包裝/修飾現有迭代器 → 繼承 IteratorIterator (實現 OuterIterator)
  • 樹狀/多層資料結構遍歷 → 實現 RecursiveIterator,配合 RecursiveIteratorIterator 使用
  • 需要隨機跳轉存取 → 實現 SeekableIterator
  • 事件通知/解耦 → 實現 SplSubject/SplObserver
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved