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

PHP 實作 Collection 類別:從基礎封裝到惰性載入進階模式

     編輯:PHP 綜合知識

前言

PHP 原生陣列功能強大,但缺乏型別約束、統一介面與物件導向封裝。參考 .NET Collection 設計,本文逐步建構一個功能完整、支援惰性載入的 PHP 集合類別。

第一階段:基礎 Collection 實作

核心需求:封裝陣列、提供型別安全介面、支援鍵值存取。

<?php
class Collection {
    private array $items = [];

    // 新增項目
    public function addItem(mixed $item, mixed $key = null): void {
        if ($key !== null) {
            if (isset($this->items[$key])) {
                throw new InvalidArgumentException("Key \"$key\" already exists.");
            }
            $this->items[$key] = $item;
        } else {
            $this->items[] = $item;
        }
    }

    // 移除項目
    public function removeItem(mixed $key): void {
        if (!isset($this->items[$key])) {
            throw new OutOfBoundsException("Invalid key \"$key\".");
        }
        unset($this->items[$key]);
    }

    // 取得項目
    public function getItem(mixed $key): mixed {
        if (!isset($this->items[$key])) {
            throw new OutOfBoundsException("Invalid key \"$key\".");
        }
        return $this->items[$key];
    }

    // 取得所有鍵
    public function keys(): array {
        return array_keys($this->items);
    }

    // 取得長度
    public function length(): int {
        return count($this->items);
    }

    // 檢查鍵是否存在
    public function exists(mixed $key): bool {
        return isset($this->items[$key]);
    }
}
?>

第二階段:型別約束與領域模型整合

搭配具體領域物件 (如 Course) 使用:

<?php
class Course {
    private int $id;
    private string $code;
    private string $name;

    public function __construct(int $id, string $code, string $name) {
        $this->id = $id;
        $this->code = $code;
        $this->name = $name;
    }

    public function getName(): string { return $this->name; }
    public function getId(): int { return $this->id; }
    public function getCode(): string { return $this->code; }
    public function __toString(): string { return $this->name; }
}

// 型別特化集合 (PHP 8.1+ 可用泛型註解或繼承限制)
class CourseCollection extends Collection {
    public function addItem(Course $item, mixed $key = null): void {
        parent::addItem($item, $key);
    }

    public function getItem(mixed $key): Course {
        return parent::getItem($key);
    }
}

// 使用
$courses = new CourseCollection();
$courses->addItem(new Course(1, '001', '國文'), 1);
$courses->addItem(new Course(2, '002', '數學'), 2);
echo $courses->getItem(1); // 輸出: 國文
?>

第三階段:惰性載入 - 核心進階模式

解決「關聯資料量大、不想預先載入」的問題。引入回調機制,首次存取時才觸發資料載入。

<?php
class LazyCollection extends Collection {
    private ?callable $loadCallback = null;
    private bool $isLoaded = false;

    // 設定載入回調
    public function setLoadCallback(callable $callback): void {
        $this->loadCallback = $callback;
    }

    // 內部:所有公開存取方法前置檢查
    private function checkCallback(): void {
        if ($this->loadCallback !== null && !$this->isLoaded) {
            $this->isLoaded = true;
            ($this->loadCallback)($this); // 傳入 $this 讓回調填充資料
        }
    }

    // 覆寫所有公開方法,加入 checkCallback()
    public function addItem(mixed $item, mixed $key = null): void {
        $this->checkCallback();
        parent::addItem($item, $key);
    }

    public function removeItem(mixed $key): void {
        $this->checkCallback();
        parent::removeItem($key);
    }

    public function getItem(mixed $key): mixed {
        $this->checkCallback();
        return parent::getItem($key);
    }

    public function keys(): array {
        $this->checkCallback();
        return parent::keys();
    }

    public function length(): int {
        $this->checkCallback();
        return parent::length();
    }

    public function exists(mixed $key): bool {
        $this->checkCallback();
        return parent::exists($key);
    }
}
?>

實戰整合:Student - Course 惰性關聯

<?php
class Student {
    private int $id;
    private string $name;
    public LazyCollection $courses;

    public function __construct(int $id, string $name) {
        $this->id = $id;
        $this->name = $name;
        $this->courses = new LazyCollection();
        // 設定回調:捕獲 $this 以便存取學生 ID 查詢課程
        $this->courses->setLoadCallback([$this, 'loadCourses']);
    }

    public function getName(): string { return $this->name; }
    public function getId(): int { return $this->id; }

    // 回調方法:實際從資料庫載入課程並填充集合
    public function loadCourses(Collection $collection): void {
        // 模擬資料庫查詢
        $courseData = [
            ['id' => 1, 'code' => '001', 'name' => '國文'],
            ['id' => 2, 'code' => '002', 'name' => '數學'],
        ];

        foreach ($courseData as $data) {
            $course = new Course($data['id'], $data['code'], $data['name']);
            $collection->addItem($course, $data['id']);
        }
    }
}

// 使用:實例化 Student 時不查詢課程
$student = new Student(1, '馬江');
echo $student->getName(); // 輸出: 馬江

// 首次存取 courses 時觸發 loadCourses()
$course = $student->courses->getItem(1);
echo $course; // 輸出: 國文 (此時才執行 SQL 查詢)
?>

進階優化方向

  • Proxy 模式:將惰性邏輯抽離為獨立 LazyCollectionProxy,符合單一職責原則。
  • 快取層整合:回調內優先檢查 Redis/Memcached,未命中再查資料庫。
  • 批次載入:多個集合同時觸發載入時,合併為單一 IN 查詢 (解決 N+1 問題)。
  • PHP 8.1+ readonly / 型別提示:強化型別安全與不可變性。

總結

從簡單陣列封裝到支援惰性載入的 LazyCollection,我們逐步建構出符合領域驅動設計 (DDD) 聚合根模式的集合類別。關鍵在於 回調注入 與 首次存取攔截,將資料獲取邏輯延遲到真正需要時刻,有效降低記憶體佔用與資料庫查詢壓力。

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