PHP8.1之enum解析

church發表於2021-12-09
PHP8.1釋出了, 一個 enum 就有好多東西要注意.

enum 基本上就是一個限定類, 先看看它的語法結構是什麼樣的.

enum_declaration_statement:
        T_ENUM { $<num>$ = CG(zend_lineno); }
        T_STRING enum_backing_type implements_list backup_doc_comment '{' class_statement_list '}'
            { $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_ENUM|ZEND_ACC_FINAL, $<num>2, $6, zend_ast_get_str($3), NULL, $5, $8, NULL, $4); }
;

enum 關鍵字打頭, 後面可選跟: (string|int), 因為是類所以可以實現介面 implement SomeInterface, MoreInterface, 又因為加了 ZEND_ACC_FINAL, 相當於 final class className, 所以是不能繼承別的列舉型別.

定義

<?php

//不初始化值,直接這樣定義是可以的
enum Week {
    case Monday;
}

//這樣是錯誤的,裡面的列舉元素初始化值,必須指定整個列舉型別的變數型別,string 或者 int
enum Week {
    case Monday = 'monday';  
}

//正確的方式
enum Week: string {
    case Monday = 'monday';
}

enum的一些特定操作

<?php
enum Week: string {
    case Monday = 'monday';
    case Tuesday = 'tuesday';
}

//獲取列舉型別元素的值
echo Week::Monday->value;

//獲取列舉型別元素的key
echo Week::Monday->name;

Week::Monday 就是這個列舉型別的一個例項,相當於普通類的 object.

注意列舉型別不能被例項化,也沒有構造和解構函式。如果用 new 去例項化 Week,會得到一個fatal error.

通過值獲取例項

enum Week: string {
    case Monday = 'monday';
    case Tuesday = 'tuesday';
}

var_dump(Week::from('monday'));
var_dump(Week::tryFrom('money'));

Week::from 返回的是 Worker::Monday,是 Week 的一個例項。tryFromfrom 的區別在於如果傳遞一個不存在的值,form 會報錯,而 tryFrom 返回的是 null.

tryFrom 配合新語法,程式碼會更加精簡.

//不使用 tryFrom
try {
    $value = Week::from('no_exists_value')->value;
} catch (Throwable $e) {
    $value = null;
}

//使用 tryFrom 加新語法
$value = Week::tryFrom('no_exists_value')?->value;
tips: fromtryFrom 方法是不能被重寫的.

enum 定義方法

enum Week: string {
    case Monday = 'monday';
    case Tuesday = 'tuesday';
    
    public function test() {
        echo 'test'. PHP_EOL;
    }
}

Week::Monday->test();

呼叫和普通類一樣,例項->方法名,所以只要牢記 Week::Monday 返回的是例項,其它操作跟類高度相似。

enum 實現介面

<?php
interface TestInterface {
    public function test();
}

interface MultiInterface {
    public function func();
}

enum Week: string implements TestInterface, MultiInterface {
    case Monday = 'monday';
    case Tuesday = 'tuesday';
    
    public function test() {
        echo 'test'. PHP_EOL;
    }

    public function func() {
        echo 'multi interface func'. PHP_EOL;
    }
}

enum使用trait

trait Testable {
    public function test() {
        echo 'test'.PHP_EOL;
    }
}

enum Week: string {
    use Testable;

    case Monday = 'monday';
    case Tuesday = 'tuesday';
}

enum 獲取例項列表

<?php

enum Week: string {
    case Monday = 'monday';
    case Tuesday = 'tuesday';
}

var_dump(Week::cases());
tips: cases 方法也不能被重寫.

判斷一個 enum 是否存在

<?php

enum Week: string {
    case Monday = 'monday';
    case Tuesday = 'tuesday';
}

var_dump(enum_exists('Week'));

其它

  1. 因為 enum 本質上還是一個類,所以有些普通類的函式,enum 也能用,比如 instanceof.
<?php

var_dump(Week::Monday instanceof Week);
  1. 使用 ::class 返回完全限定名,同樣適用於 enum 型別.
  2. 名稱空間也基本和類一致.
  3. 定義字串,也可以用 heredoc 語法.
<?php

enum Week: string {
    const Monday = <<<MONDAY
This is monday.
MONDAY;
}

ENUM和普通類的對比

ENUM普通類
建構函式不支援支援
解構函式不支援支援
序列化函式不支援支援
反序列化函式不支援支援
克隆函式不支援支援
類屬性不支援支援
動態屬性不支援支援
用 new 例項化不支援支援

相關文章