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

PHP 實現 Enum(枚舉)的多種方案:SPL 擴展與自定義類庫

     編輯:PHP 相關知識

前言

PHP 核心語言未內建 Enum 類型(直到 PHP 8.1 才引入原生 Enum),歷史上主要通過 SPL 擴展 SplEnum 或自定義類庫模擬枚舉行為。本文詳細對比兩種方案的用法與優劣。

方案一:SPL 擴展 SplEnum(需安裝 PECL spl_types)

類結構:

SplEnum extends SplType {
    const NULL __default = null;
    public array getConstList([bool $include_default = false]);
    /* 繼承 SplType::__construct([mixed $initial_value[, bool $strict]]) */
}

使用範例:月份枚舉

<?php
class Month extends SplEnum {
    const __default = self::January;
    const January = 1; const February = 2; const March = 3;
    const April = 4; const May = 5; const June = 6;
    const July = 7; const August = 8; const September = 9;
    const October = 10; const November = 11; const December = 12;
}

echo new Month(Month::June) . PHP_EOL; // 輸出 6

try {
    new Month(13); // 非法值
} catch (UnexpectedValueException $uve) {
    echo $uve->getMessage() . PHP_EOL; // 輸出 "Value not a const in enum Month"
}
?>

優點:原生級效能、嚴格類型檢查、支援預設值。
缺點:需額外安裝擴展,部署環境受限,非標準分發。

方案二:純 PHP 自定義 Enum 基類(零依賴,通用性強)

來源:php4every1.com

核心基類實現

<?php
abstract class Enum {
    const __default = null;
    private $value;
    private $strict;
    private static $constants = [];

    public function getConstList($includeDefault = false) {
        $class = get_class($this);
        if (!array_key_exists($class, self::$constants)) self::populateConstants();
        return $includeDefault ? array_merge(self::$constants[$class], ["__default" => self::__default]) : self::$constants[$class];
    }

    public function __construct($initialValue = null, $strict = true) {
        $class = get_class($this);
        if (!array_key_exists($class, self::$constants)) self::populateConstants();
        if ($initialValue === null) $initialValue = self::$constants[$class]["__default"];
        $temp = self::$constants[$class];
        if (!in_array($initialValue, $temp, $strict)) throw new UnexpectedValueException("Value is not in enum $class");
        $this->value = $initialValue; $this->strict = $strict;
    }

    private function populateConstants() {
        $class = get_class($this);
        $r = new ReflectionClass($class);
        self::$constants[$class] = $r->getConstants();
    }

    public function __toString() { return (string) $this->value; }

    public function equals($object) {
        if (!($object instanceof Enum)) return false;
        return $this->strict ? ($this->value === $object->value) : ($this->value == $object->value);
    }
}
?>

使用範例:自定義枚舉

<?php
class MyEnum extends Enum {
    const HI = "Hi";
    const BY = "By";
    const NUMBER = 1;
    const __default = self::BY;
}

var_dump(new MyEnum(MyEnum::HI));
var_dump(new MyEnum(MyEnum::BY));
var_dump(new MyEnum()); // 使用預設值 BY

try {
    new MyEnum("I don't exist");
} catch (UnexpectedValueException $e) {
    var_dump($e->getMessage()); // "Value is not in enum MyEnum"
}
?>

輸出:正確實例化並拋出異常阻擋非法值。

特性總結

  • 支援字符串、整數等任意常量值。
  • 自動緩存反射獲取的常量列表,效能優化。
  • __toString() 直接輸出值,方便模板引擎使用。
  • equals() 支援嚴格/非嚴格比較。

方案對比與建議

維度SplEnum自定義基類
依賴需安裝 PECL spl_types零依賴,純 PHP
效能C 層實現,極快反射緩存後接近原生
部署需服務器權限安裝擴展代碼即用,適合共享主機
功能基礎枚舉行為可擴展(如添加標籤、描述)

現代 PHP(8.1+)原生 Enum

PHP 8.1 引入原生 enum 關鍵字,支援純枚舉和有背景值枚舉,且具備方法、介面實現等豐富特性:

<?php
enum Status: string {
    case Draft = 'draft';
    case Published = 'published';
    case Archived = 'archived';

    public function label(): string {
        return match($this) {
            self::Draft => '草稿',
            self::Published => '已發布',
            self::Archived => '已歸檔',
        };
    }
}

$status = Status::Published;
echo $status->value; // 'published'
echo $status->label(); // '已發布'
?>

建議:新項目若環境允許,優先使用 PHP 8.1+ 原生 Enum;舊項目或受限環境,自定義基類是最佳替代方案。

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