timetoogo/enums

支持PHP 5.4+的枚举

1.0.6 2014-01-19 13:09 UTC

This package is auto-updated.

Last update: 2024-08-25 07:02:47 UTC


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());