PHP的Enum(枚举)的实现
PHP其实有Enum类库的,需要安装perl扩展,所以不是php的标准扩展,因此代码的实现需要运行的php环境支持。
(1)扩展类库SplEnum类。该类的摘要如下:
SplEnum extends SplType { /* Constants */ 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; try { new Month(13); } catch (UnexpectedValueException $uve ) { echo $uve ->getMessage() . PHP_EOL; } ?>
输出结果:
6
Value not a const in enum Month
(2)自定义的Enum类库
摘自http://www.php4every1.com/scripts/php-enum/
<?php
/**
* Abstract class that enables creation of PHP enums. All you
* have to do is extend this class and define some constants.
* Enum is an object with value from on of those constants
* (or from on of superclass if any). There is also
* __default constat that enables you creation of object
* without passing enum value.
*
* @author Marijan Šuflaj <msufflaj32@gmail.com>
* @link http://php4every1.com
*/
abstract
class
Enum {
/**
* Constant with default value for creating enum object
*/
const
__default = null;
private
$value
;
private
$strict
;
private
static
$constants
=
array
();
/**
* Returns list of all defined constants in enum class.
* Constants value are enum values.
*
* @param bool $includeDefault If true, default value is included into return
* @return array Array with constant values
*/
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_],
array
(
"__default"
=> self::__default
)) : self::
$constants
[__CLASS_];
}
/**
* Creates new enum object. If child class overrides __construct(),
* it is required to call parent::__construct() in order for this
* class to work as expected.
*
* @param mixed $initialValue Any value that is exists in defined constants
* @param bool $strict If set to true, type and value must be equal
* @throws UnexpectedValueException If value is not valid enum value
*/
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
);
$constants
=
$r
->getConstants();
self::
$constants
=
array
(
$class
=>
$constants
);
}
/**
* Returns string representation of an enum. Defaults to
* value casted to string.
*
* @return string String representation of this enum's value
*/
public
function
__toString() {
return
(string)
$this
->value;
}
/**
* Checks if two enums are equal. Only value is checked, not class type also.
* If enum was created with $strict = true, then strict comparison applies
* here also.
*
* @return bool True if enums are equal
*/
public
function
equals(
$object
) {
if
(!(
$object
instanceof
Enum)) {
return
false;
}
return
$this
->strict ? (
$this
->value ===
$object
->value)
: (
$this
->value ==
$object
->value);
}
}
使用示例如下:
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)); //Use __default var_dump( new MyEnum()); try { new MyEnum( "I don't exist" ); } catch (UnexpectedValueException $e ) { var_dump( $e ->getMessage()); }
输出结果如下:
object(MyEnum)#1 (2) { ["value":"Enum":private]=> string(2) "Hi" ["strict":"Enum":private]=> bool(true) } object(MyEnum)#1 (2) { ["value":"Enum":private]=> string(2) "By" ["strict":"Enum":private]=> bool(true) } object(MyEnum)#1 (2) { ["value":"Enum":private]=> string(2) "By" ["strict":"Enum":private]=> bool(true) } string(27) "Value is not in enum MyEnum"