timetoogo / enums
支持PHP 5.4+的枚举
1.0.6
2014-01-19 13:09 UTC
Requires
- php: >=5.4.0
README
安装
将包添加到 composer.json
。
{ "require": { "timetoogo/enums": "*" } }
或者手动 require {Path to Enum}/Loader.php
总结
- 枚举是一组可能的值:
DayOfWeek
- 枚举的一个实例表示一个基础值:
DayOfWeek::Thursday()->GetValue()
- 两个代表相同值的枚举实例是相同的:
DayOfWeek::Thursday() === DayOfWeek::Thursday()
- 枚举是类型安全的:
function SetDay(DayOfWeek $DayOfWeek)
- 枚举是可扩展的:
DayOfWeek::Thursday()->GetTomorrow()
- 枚举值是可以序列化的:
DayOfWeek::Serialize(DayOfWeek::Thursday())
- 枚举值可以表示为字符串:
(string)DayOfWeek::Thursday()
简介
final class Boolean extends \Enum\Simple { public static function True() { return self::Representing('True'); } public static function False() { return self::Representing('False'); } }
恭喜,我们已经成功用枚举重新实现了布尔值。
我们来测试一下
var_export(Boolean::True() === Boolean::True()); //true var_export(Boolean::True() === Boolean::False()); //false var_export(Boolean::False() === Boolean::False()); //true
太好了,它工作了,现在让我们重新实现 !
操作符。
final class Boolean extends \Enum\Simple { public static function True() { return self::Representing('True'); } public static function False() { return self::Representing('False'); } public function Not() { return $this === self::True() ? self::False() : self::True(); } }
并测试它
Boolean::True()->Not() === Boolean::True(); //false Boolean::True() === Boolean::False()->Not(); //true Boolean::False()->Not()->Not() === Boolean::False(); //true
不错,但没有什么意义。
让我们做一些有用的事情,创建一周中的几天(如总结中所述)
final class DayOfWeek extends Enum\Simple { public static function Monday() { return self::Representing('Monday'); } public static function Tuesday() { return self::Representing('Tuesday'); } public static function Wednesday() { return self::Representing('Wednesday'); } public static function Thursday() { return self::Representing('Thursday'); } public static function Friday() { return self::Representing('Friday'); } public static function Saturday() { return self::Representing('Saturday'); } public static function Sunday() { return self::Representing('Sunday'); } public function GetTomorrow() { if($this === self::Sunday()) { return self::Monday(); } else { $All = self::All(); return $All[array_search($this, $All) + 1]; } } }
注意到了吗?枚举值简单地用它们的名称表示。
好吧,让我们保持 DRY 看看我们会走多远
final class DayOfWeek extends Enum\Simple { public static function Monday() { return self::Representing(__FUNCTION__); } public static function Tuesday() { return self::Representing(__FUNCTION__); } public static function Wednesday() { return self::Representing(__FUNCTION__); } public static function Thursday() { return self::Representing(__FUNCTION__); } public static function Friday() { return self::Representing(__FUNCTION__); } public static function Saturday() { return self::Representing(__FUNCTION__); } public static function Sunday() { return self::Representing(__FUNCTION__); } public function GetTomorrow() { if($this === self::Sunday()) { return self::Monday(); } else { $All = self::All(); return $All[array_search($this, $All) + 1]; } } }
好吧,这并没有做很多事情,而且仍然非常冗长!而且很丑。
放松,有一个解决方案
```php final class DayOfWeek extends \Enum\Simple { use \Enum\Values { _ as Monday; _ as Tuesday; _ as Wednesday; _ as Thursday; _ as Friday; _ as Saturday; _ as Sunday; }public function GetTomorrow() { if($this === self::Sunday()) { return self::Monday(); } else { $All = self::All(); return $All[array_search($this, $All) + 1]; } }
}
这好多了!注意,上述三个示例在功能上没有区别。**注意,使用 `\Enum\Values` 仅适用于 PHP >5.4.16** 如果您的枚举值用方法名表示,您可以使用 `\Enum\Values` 特性。这个特性包含一个静态方法 `_`。您可以将其别名到所需的枚举值,并使用别名的方法将返回表示方法名字符串的枚举。使用此特性,等效的布尔值将变为:```php final class Boolean extends \Enum\Simple { use \Enum\Values { _ as True; _ as False; } public function Not() { return $this === self::True() ? self::False() : self::True(); } }
转换为字符串
重写 protected string ToString(mixed $Value)
来自定义转换为字符串
final class DayOfWeek extends \Enum\Simple { use \Enum\Values { _ as Monday; _ as Tuesday; _ as Wednesday; _ as Thursday; _ as Friday; _ as Saturday; _ as Sunday; } protected function ToString($Value) { return 'Today could be ' . strtolower($Value) . '.'; } } echo DayOfWeek::Saturday(); //Today could be saturday.
序列化
枚举值也可以使用 Enum\Base::Serialize(Enum\Base $Enum)
和 Enum\Base::Unserialize(string $SerializedEnum)
分别进行完全序列化/反序列化。这适用于任何定义的枚举。
如果您想对特定类型的枚举进行反序列化,您可以在所需枚举类型的上下文中调用任一方法
$Monday = DayOfWeek::Monday(); $SerializedMonday = Enum\Base::Serialize($Monday);//Ok $SerializedMonday = DayOfWeek::Serialize($Monday);//Ok $SerializedMonday = MonthOfYear::Serialize($Monday);//ERROR! $Monday = Enum\Base::Unserialize($SerializedMonday); //Ok $Monday = DayOfWeek::Unserialize($SerializedMonday); //Ok $Monday = MonthOfYear::Unserialize($SerializedMonday); //ERROR!
比较和相等
相同类型的两个枚举实例,表示相同的值必须是相等的。以下是用 ===
操作符进行比较的结果。
$Monday = DayOfWeek::Monday(); $Tuesday = DayOfWeek::Tuesday(); $Monday === DayOfWeek::Monday(); //true $Monday === DayOfWeek::FromValue(DayOfWeek::Monday()->GetValue()); //true $Monday === DayOfWeek::Unserialize(DayOfWeek::Serialize(DayOfWeek::Monday())); //true $Monday === $Tuesday; //false
如您所见,枚举中始终只有一个实例表示任何给定的值。
清晰的API理解
Enum\Base::Map(callable $MappingCallback)
将枚举实例映射到提供的回调函数Enum\Base::MapValues(callable $MappingCallback)
将表示的值与提供的回调映射Enum\Base::Filter(callable $MappingCallback)
使用提供的回调过滤枚举实例Enum\Base::FilterByValue(callable $MappingCallback)
使用提供的回调根据枚举的表示值过滤枚举Enum\Base::FirstOrDefault(callable $MappingCallback)
根据过滤回调返回第一个枚举,如果没有匹配则返回默认值FirstOrDefaultByValue(callable $MappingCallback)
用法
final class DayOfWeek extends \Enum\Simple { use \Enum\Values { _ as Monday; _ as Tuesday; _ as Wednesday; _ as Thursday; _ as Friday; _ as Saturday; _ as Sunday; } public static function IsWeekEnd(self $DayOfWeek) { return $DayOfWeek === self::Saturday() || $DayOfWeek === self::Sunday(); } public static function GetWeekDays() { return self::Filter(function (self $DayOfWeek) { return !self::IsWeekEnd($DayOfWeek); }); } public static function GetWeekEndDays() { return self::Filter([__CLASS__, 'IsWeekEnd']); } }
一个更复杂的示例
如果您的需求更复杂,枚举可以表示任何可序列化的值
class Country extends Enum\Simple { public static function USA() { return self::Representing( [ 'Name' => 'United States of America', 'Population' => 317500000, 'Area' => 9826675 ]); } public static function Australia() { return self::Representing( [ 'Name' => 'Australia', 'Population' => 23351119, 'Area' => 7692024 ]); } public static function SouthAfrica() { return self::Representing( [ 'Name' => 'South Africa', 'Population' => 52981991, 'Area' => 1221037 ]); } public static function FromName($Name) { return self::FirstOrDefaultByValue( function ($Value) use ($Name) { return $Value['Name'] === $Name; }); } protected function ToString($Value) { return $Value['Name']; } public function PopulationDensity() { $Country = $this->GetValue(); return $Country['Population'] / $Country['Area']; } }
我们定义了一个表示某些国家的枚举,并提供了一些方法来获取该数据的信息。
用法
$SouthAfrica = Country::SouthAfrica(); echo sprintf('%s has a population density of: %s/Km²', $SouthAfrica, $SouthAfrica->PopulationDensity());