一種常見的方式是,使用常量來代表枚舉類型
1
2
3
|
const YES = '是' ; const NO = '否' ; |
可以在這個基礎上更進一步,將其封裝成類,以便于管理
1
2
3
4
5
6
7
|
class BoolEnum { const YES = '是' ; const NO = '否' ; } |
現在,我們希望能通過方法來動態調用對應的枚舉類型
1
2
3
|
BoolEnum::YES(); // 是 BoolEnum::NO(); // 否 |
也可以批量獲取枚舉類型
1
|
BoolEnum::toArray(); // ['Yes' => '是', 'No' => '否'] |
下面來實現上面列舉的功能。
定義基本的枚舉基類,讓所有的枚舉類都繼承該抽象基類。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
abstract class Enum { // 獲取所有枚舉類型 public static function toArray(){ // 通過反射獲取常量 $reflection = new \ReflectionClass( static :: class ); $contants = $reflection ->getConstants(); // 返回對應的常量 return $contants ; } // 動態調用屬性 public static function __callStatic( $name , $arguments ) { $arr = static ::toArray(); if (isset( $arr [ $name ])){ return $arr [ $name ]; } throw new \BadMethodCallException( "找不到對應的枚舉值 {$name}" ); } } class BoolEnum extends Enum { const YES = '是' ; const NO = '否' ; } |
利用反射,可以獲取到所有的枚舉類型。同時,利用魔術方法則可以實現對屬性的動態調用。這里要注意的是,反射會消耗較多的資源,因此,對 toArray 方法進行重構,增加一個緩存變量來緩存獲取到的枚舉類型,避免重復使用反射。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
abstract class Enum { protected static $cache = []; public static function toArray(){ $class = static :: class ; // 第一次獲取,就通過反射來獲取 if (! isset( static :: $cache [ $class ])){ $reflection = new \ReflectionClass( static :: class ); static :: $cache [ $class ] = $reflection ->getConstants(); } return static :: $cache [ $class ]; } } |
現在考慮更多的使用場景,比如用實例來代表特定枚舉類型
1
2
3
|
$yes = new BoolEnum( "是" ); echo $yes ; // "是" |
實現如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
abstract Enum { protected $value ; public function __construct( $value ) { if ( $value instanceof static ) { $value = $value ->getValue(); } if (! $this ->isValid( $value )){ throw new \UnexpectedValueException( "$value 不屬于該枚舉值" . static :: class ); } $this ->value = $value ; } // 獲取實例對應的鍵 public function getKey(){ return array_search ( $this ->value, static ::toArray(), true); } // 獲取實例對應的值 public function getValue() { return $this ->value; } // 允許字符串形式輸出 public function __toString() { return $this ->value; } // 驗證值是否合法 public function isValid( $value ) { $arr = static ::toArray(); return in_array( $value , $arr , true); } // 驗證鍵是否合法 public function isValidKey( $key ) { $arr = static ::toArray(); return array_key_exists ( $key , $arr ); } } |
這樣做可避免用戶使用非法的枚舉類型的值
1
2
3
4
5
|
$user ->banned = '非法值' ; // 可能不會報錯 $yes = new BoolEnum( "非法值" ); // 將會拋出異常 $user ->banned = $yes ; |
或者作為參數類型限定
1
2
3
4
5
|
function setUserStatus(BoolEnum $boolEnum ){ $user ->banned = $boolEnum ; } |
PHP 作為一門弱類型語言,參數限定的不足會導致很多不可預期的錯誤發生,通過使用枚舉類,我們進一步加強了參數限定的功能,同時,管理枚舉類型也更加的方便統一。
以上就是本次介紹的全部相關知識點,感謝大家的學習和對服務器之家的支持。
原文鏈接:https://www.php.cn/php-weizijiaocheng-442653.html