cerbero/enum

PHP 库,用于扩展枚举功能。

1.0.0 2022-07-12 14:00 UTC

This package is auto-updated.

Last update: 2024-09-15 16:18:42 UTC


README

Author PHP Version Build Status Coverage Status Quality Score PHPStan Level Latest Version Software License PER Total Downloads

零依赖的 PHP 库,用于增强枚举功能。

📦 安装

Via Composer

composer require cerbero/enum

🔮 使用方法

要使用此包提供的所有功能来增强我们的枚举,我们可以在纯枚举和后端枚举中使用 Enumerates 特性

use Cerbero\Enum\Concerns\Enumerates;

enum PureEnum
{
    use Enumerates;

    case one;
    case two;
    case three;
}

enum BackedEnum: int
{
    use Enumerates;

    case one = 1;
    case two = 2;
    case three = 3;
}

分类

这些方法确定枚举是纯的还是后端的

PureEnum::isPure(); // true
PureEnum::isBacked(); // false

BackedEnum::isPure(); // false
BackedEnum::isBacked(); // true

比较

我们可以检查枚举是否包含某些名称或值。纯枚举检查名称,而后端枚举检查值

PureEnum::has('one'); // true
PureEnum::has('four'); // false
PureEnum::doesntHave('one'); // false
PureEnum::doesntHave('four'); // true

BackedEnum::has(1); // true
BackedEnum::has(4); // false
BackedEnum::doesntHave(1); // false
BackedEnum::doesntHave(4); // true

否则,我们可以让案例确定它们是否与名称或值匹配

PureEnum::one->is('one'); // true
PureEnum::one->is(1); // false
PureEnum::one->is('four'); // false
PureEnum::one->isNot('one'); // false
PureEnum::one->isNot(1); // true
PureEnum::one->isNot('four'); // true

BackedEnum::one->is(1); // true
BackedEnum::one->is('1'); // false
BackedEnum::one->is(4); // false
BackedEnum::one->isNot(1); // false
BackedEnum::one->isNot('1'); // true
BackedEnum::one->isNot(4); // true

比较也可以在数组内进行

PureEnum::one->in(['one', 'four']); // true
PureEnum::one->in([1, 4]); // false
PureEnum::one->notIn('one', 'four'); // false
PureEnum::one->notIn([1, 4]); // true

BackedEnum::one->in([1, 4]); // true
BackedEnum::one->in(['one', 'four']); // false
BackedEnum::one->notIn([1, 4]); // false
BackedEnum::one->notIn(['one', 'four']); // true

键解析

当我们提到“键”时,我们指的是在枚举中定义的任何元素,例如名称、值或案例实现的函数。以下是一个枚举的例子

enum BackedEnum: int
{
    use Enumerates;

    case one = 1;
    case two = 2;
    case three = 3;

    public function color(): string
    {
        return match ($this) {
            static::one => 'red',
            static::two => 'green',
            static::three => 'blue',
        };
    }

    public function isOdd(): bool
    {
        return match ($this) {
            static::one => true,
            static::two => false,
            static::three => true,
        };
    }
}

在此枚举中定义的键是 namevalue(因为它是一个后端枚举)、colorisOdd。我们可以通过调用 get() 来检索分配给案例的任何键

PureEnum::one->get('name'); // 'one'
PureEnum::one->get('value'); // throws ValueError as it is a pure enum
PureEnum::one->get('color'); // 'red'
PureEnum::one->get(fn (PureEnum $caseOne) => $caseOne->isOdd()); // true

BackedEnum::one->get('name'); // 'one'
BackedEnum::one->get('value'); // 1
BackedEnum::one->get('color'); // 'red'
BackedEnum::one->get(fn (BackedEnum $caseOne) => $caseOne->isOdd()); // true

乍一看,此方法可能显得有些过度,因为“键”可以直接像这样通过案例访问

BackedEnum::one->name; // 'one'
BackedEnum::one->value; // 1
BackedEnum::one->color(); // 'red'
BackedEnum::one->isOdd(); // true

然而,get() 对于动态解析键非常有用,因为键可能是一个属性、一个方法或一个闭包。它通常用于实现更高级的功能,我们很快就会探索这些功能。

初始化

枚举案例可以从其名称、值(如果后端)和 实例化

PureEnum::from('one'); // PureEnum::one
PureEnum::from('four'); // throws ValueError
PureEnum::tryFrom('one'); // PureEnum::one
PureEnum::tryFrom('four'); // null
PureEnum::fromName('one'); // PureEnum::one
PureEnum::fromName('four'); // throws ValueError
PureEnum::tryFromName('one'); // PureEnum::one
PureEnum::tryFromName('four'); // null
PureEnum::fromKey('name', 'one'); // CasesCollection<PureEnum::one>
PureEnum::fromKey('value', 1); // throws ValueError
PureEnum::fromKey('color', 'red'); // CasesCollection<PureEnum::one>
PureEnum::fromKey(fn (PureEnum $case) => $case->isOdd(), true); // CasesCollection<PureEnum::one, PureEnum::three>
PureEnum::tryFromKey('name', 'one'); // CasesCollection<PureEnum::one>
PureEnum::tryFromKey('value', 1); // null
PureEnum::tryFromKey('color', 'red'); // CasesCollection<PureEnum::one>
PureEnum::tryFromKey(fn (PureEnum $case) => $case->isOdd(), true); // CasesCollection<PureEnum::one, PureEnum::three>

BackedEnum::from(1); // BackedEnum::one
BackedEnum::from('1'); // throws ValueError
BackedEnum::tryFrom(1); // BackedEnum::one
BackedEnum::tryFrom('1'); // null
BackedEnum::fromName('one'); // BackedEnum::one
BackedEnum::fromName('four'); // throws ValueError
BackedEnum::tryFromName('one'); // BackedEnum::one
BackedEnum::tryFromName('four'); // null
BackedEnum::fromKey('name', 'one'); // CasesCollection<BackedEnum::one>
BackedEnum::fromKey('value', 1); // CasesCollection<BackedEnum::one>
BackedEnum::fromKey('color', 'red'); // CasesCollection<BackedEnum::one>
BackedEnum::fromKey(fn (BackedEnum $case) => $case->isOdd(), true); // CasesCollection<BackedEnum::one, BackedEnum::three>
BackedEnum::tryFromKey('name', 'one'); // CasesCollection<BackedEnum::one>
BackedEnum::tryFromKey('value', 1); // CasesCollection<BackedEnum::one>
BackedEnum::tryFromKey('color', 'red'); // CasesCollection<BackedEnum::one>
BackedEnum::tryFromKey(fn (BackedEnum $case) => $case->isOdd(), true); // CasesCollection<BackedEnum::one, BackedEnum::three>

虽然纯枚举试图从名称中初始化案例,但后端枚举可以同时从名称和值中初始化。甚至键也可以用于初始化案例,然后案例被包装到 CasesCollection 中以允许进一步处理。

详细说明案例

可以对枚举的案例执行一系列操作。如果操作的最终结果是一个简单的案例列表,它们将包装到一个 CasesCollection 中以进行进一步处理,否则返回操作的最后结果。

PureEnum::collect(); // CasesCollection<PureEnum::one, PureEnum::two, PureEnum::three>
PureEnum::count(); // 3
PureEnum::casesByName(); // ['one' => PureEnum::one, 'two' => PureEnum::two, 'three' => PureEnum::three]
PureEnum::casesByValue(); // []
PureEnum::casesBy('color'); // ['red' => PureEnum::one, 'green' => PureEnum::two, 'blue' => PureEnum::three]
PureEnum::groupBy('color'); // ['red' => [PureEnum::one], 'green' => [PureEnum::two], 'blue' => [PureEnum::three]]
PureEnum::names(); // ['one', 'two', 'three']
PureEnum::values(); // []
PureEnum::pluck(); // ['one', 'two', 'three']
PureEnum::pluck('color'); // ['red', 'green', 'blue']
PureEnum::pluck(fn (PureEnum $case) => $case->isOdd()); // [true, false, true]
PureEnum::pluck('color', 'shape'); // ['triangle' => 'red', 'square' => 'green', 'circle' => 'blue']
PureEnum::pluck(fn (PureEnum $case) => $case->isOdd(), fn (PureEnum $case) => $case->name); // ['one' => true, 'two' => false, 'three' => true]
PureEnum::filter('isOdd'); // CasesCollection<PureEnum::one, PureEnum::three>
PureEnum::filter(fn (PureEnum $case) => $case->isOdd()); // CasesCollection<PureEnum::one, PureEnum::three>
PureEnum::only('two', 'three'); // CasesCollection<PureEnum::two, PureEnum::three>
PureEnum::except('two', 'three'); // CasesCollection<PureEnum::one>
PureEnum::onlyValues(2, 3); // CasesCollection<>
PureEnum::exceptValues(2, 3); // CasesCollection<>
PureEnum::sort(); // CasesCollection<PureEnum::one, PureEnum::three, PureEnum::two>
PureEnum::sortDesc(); // CasesCollection<PureEnum::two, PureEnum::three, PureEnum::one>
PureEnum::sortByValue(); // CasesCollection<>
PureEnum::sortDescByValue(); // CasesCollection<>
PureEnum::sortBy('color'); // CasesCollection<PureEnum::three, PureEnum::two, PureEnum::one>
PureEnum::sortDescBy(fn (PureEnum $case) => $case->color()); // CasesCollection<PureEnum::one, PureEnum::two, PureEnum::three>

BackedEnum::collect(); // CasesCollection<BackedEnum::one, BackedEnum::two, BackedEnum::three>
BackedEnum::count(); // 3
BackedEnum::casesByName(); // ['one' => BackedEnum::one, 'two' => BackedEnum::two, 'three' => BackedEnum::three]
BackedEnum::casesByValue(); // [1 => BackedEnum::one, 2 => BackedEnum::two, 3 => BackedEnum::three]
BackedEnum::casesBy('color'); // ['red' => BackedEnum::one, 'green' => BackedEnum::two, 'blue' => BackedEnum::three]
BackedEnum::groupBy('color'); // ['red' => [BackedEnum::one], 'green' => [BackedEnum::two], 'blue' => [BackedEnum::three]]
BackedEnum::names(); // ['one', 'two', 'three']
BackedEnum::values(); // [1, 2, 3]
BackedEnum::pluck(); // [1, 2, 3]
BackedEnum::pluck('color'); // ['red', 'green', 'blue']
BackedEnum::pluck(fn (BackedEnum $case) => $case->isOdd()); // [true, false, true]
BackedEnum::pluck('color', 'shape'); // ['triangle' => 'red', 'square' => 'green', 'circle' => 'blue']
BackedEnum::pluck(fn (BackedEnum $case) => $case->isOdd(), fn (BackedEnum $case) => $case->name); // ['one' => true, 
BackedEnum::filter('isOdd'); // CasesCollection<BackedEnum::one, BackedEnum::three>
BackedEnum::filter(fn (BackedEnum $case) => $case->isOdd()); // CasesCollection<BackedEnum::one, BackedEnum::three>
BackedEnum::only('two', 'three'); // CasesCollection<BackedEnum::two, BackedEnum::three>
BackedEnum::except('two', 'three'); // CasesCollection<BackedEnum::one>
BackedEnum::onlyValues(2, 3); // CasesCollection<>
BackedEnum::exceptValues(2, 3); // CasesCollection<>'two' => false, 'three' => true]
BackedEnum::sort(); // CasesCollection<BackedEnum::one, BackedEnum::three, BackedEnum::two>
BackedEnum::sortDesc(); // CasesCollection<BackedEnum::two, BackedEnum::three, BackedEnum::one>
BackedEnum::sortByValue(); // CasesCollection<BackedEnum::one, BackedEnum::two, BackedEnum::three>
BackedEnum::sortDescByValue(); // CasesCollection<BackedEnum::three, BackedEnum::two, BackedEnum::one>
BackedEnum::sortBy('color'); // CasesCollection<BackedEnum::three, BackedEnum::two, BackedEnum::one>
BackedEnum::sortDescBy(fn (BackedEnum $case) => $case->color()); // CasesCollection<BackedEnum::one, BackedEnum::two, BackedEnum::three>

案例集合

当一个简单的案例列表由 案例操作 返回时,它被包装到一个 CasesCollection 中,该集合提供了一个流畅的 API 来执行对案例集的进一步操作。

PureEnum::filter('isOdd')->sortBy('color')->pluck('color', 'name'); // ['three' => 'blue', 'one' => 'red']

可以通过调用 collect() 或任何其他 案例操作 返回 CasesCollection 来收集案例

PureEnum::collect(); // CasesCollection<PureEnum::one, PureEnum::two, PureEnum::three>

BackedEnum::only('one', 'two'); // CasesCollection<BackedEnum::one, BackedEnum::two>

我们可以在任何循环中迭代案例集合

foreach (PureEnum::collect() as $case) {
    echo $case->name;
}

获取底层简单案例列表很容易

PureEnum::collect()->cases(); // [PureEnum::one, PureEnum::two, PureEnum::three]

有时我们可能需要提取集合中的第一个案例

PureEnum::filter(fn (PureEnum $case) => !$case->isOdd())->first(); // PureEnum::two

为了参考,以下是 CasesCollection 中所有可用的操作

PureEnum::collect()->cases(); // [PureEnum::one, PureEnum::two, PureEnum::three]
PureEnum::collect()->count(); // 3
PureEnum::collect()->first(); // PureEnum::one
PureEnum::collect()->keyByName(); // ['one' => PureEnum::one, 'two' => PureEnum::two, 'three' => PureEnum::three]
PureEnum::collect()->keyByValue(); // []
PureEnum::collect()->keyBy('color'); // ['red' => PureEnum::one, 'green' => PureEnum::two, 'blue' => PureEnum::three]
PureEnum::collect()->groupBy('color'); // ['red' => [PureEnum::one], 'green' => [PureEnum::two], 'blue' => [PureEnum::three]]
PureEnum::collect()->names(); // ['one', 'two', 'three']
PureEnum::collect()->values(); // []
PureEnum::collect()->pluck(); // ['one', 'two', 'three']
PureEnum::collect()->pluck('color'); // ['red', 'green', 'blue']
PureEnum::collect()->pluck(fn (PureEnum $case) => $case->isOdd()); // [true, false, true]
PureEnum::collect()->pluck('color', 'shape'); // ['triangle' => 'red', 'square' => 'green', 'circle' => 'blue']
PureEnum::collect()->pluck(fn (PureEnum $case) => $case->isOdd(), fn (PureEnum $case) => $case->name); // ['one' => true, 'two' => false, 'three' => true]
PureEnum::collect()->filter('isOdd'); // CasesCollection<PureEnum::one, PureEnum::three>
PureEnum::collect()->filter(fn (PureEnum $case) => $case->isOdd()); // CasesCollection<PureEnum::one, PureEnum::three>
PureEnum::collect()->only('two', 'three'); // CasesCollection<PureEnum::two, PureEnum::three>
PureEnum::collect()->except('two', 'three'); // CasesCollection<PureEnum::one>
PureEnum::collect()->onlyValues(2, 3); // CasesCollection<>
PureEnum::collect()->exceptValues(2, 3); // CasesCollection<>
PureEnum::collect()->sort(); // CasesCollection<PureEnum::one, PureEnum::three, PureEnum::two>
PureEnum::collect()->sortDesc(); // CasesCollection<PureEnum::two, PureEnum::three, PureEnum::one>
PureEnum::collect()->sortByValue(); // CasesCollection<>
PureEnum::collect()->sortDescByValue(); // CasesCollection<>
PureEnum::collect()->sortBy('color'); // CasesCollection<PureEnum::three, PureEnum::two, PureEnum::one>
PureEnum::collect()->sortDescBy(fn (PureEnum $case) => $case->color()); // CasesCollection<PureEnum::one, PureEnum::two, PureEnum::three>

BackedEnum::collect()->cases(); // [BackedEnum::one, BackedEnum::two, BackedEnum::three]
BackedEnum::collect()->count(); // 3
BackedEnum::collect()->first(); // BackedEnum::one
BackedEnum::collect()->keyByName(); // ['one' => BackedEnum::one, 'two' => BackedEnum::two, 'three' => BackedEnum::three]
BackedEnum::collect()->keyByValue(); // [1 => BackedEnum::one, 2 => BackedEnum::two, 3 => BackedEnum::three]
BackedEnum::collect()->keyBy('color'); // ['red' => BackedEnum::one, 'green' => BackedEnum::two, 'blue' => BackedEnum::three]
BackedEnum::collect()->groupBy('color'); // ['red' => [BackedEnum::one], 'green' => [BackedEnum::two], 'blue' => [BackedEnum::three]]
BackedEnum::collect()->names(); // ['one', 'two', 'three']
BackedEnum::collect()->values(); // [1, 2, 3]
BackedEnum::collect()->pluck(); // [1, 2, 3]
BackedEnum::collect()->pluck('color'); // ['red', 'green', 'blue']
BackedEnum::collect()->pluck(fn (BackedEnum $case) => $case->isOdd()); // [true, false, true]
BackedEnum::collect()->pluck('color', 'shape'); // ['triangle' => 'red', 'square' => 'green', 'circle' => 'blue']
BackedEnum::collect()->pluck(fn (BackedEnum $case) => $case->isOdd(), fn (BackedEnum $case) => $case->name); // ['one' => true, 'two' => false, 'three' => true]
BackedEnum::collect()->filter('isOdd'); // CasesCollection<BackedEnum::one, BackedEnum::three>
BackedEnum::collect()->filter(fn (BackedEnum $case) => $case->isOdd()); // CasesCollection<BackedEnum::one, BackedEnum::three>
BackedEnum::collect()->only('two', 'three'); // CasesCollection<BackedEnum::two, BackedEnum::three>
BackedEnum::collect()->except('two', 'three'); // CasesCollection<BackedEnum::one>
BackedEnum::collect()->onlyValues(2, 3); // CasesCollection<BackedEnum::two, BackedEnum::three>
BackedEnum::collect()->exceptValues(2, 3); // CasesCollection<BackedEnum::one>
BackedEnum::collect()->sort(); // CasesCollection<BackedEnum::one, BackedEnum::three, BackedEnum::two>
BackedEnum::collect()->sortDesc(); // CasesCollection<BackedEnum::two, BackedEnum::three, BackedEnum::one>
BackedEnum::collect()->sortByValue(); // CasesCollection<BackedEnum::one, BackedEnum::two, BackedEnum::three>
BackedEnum::collect()->sortDescByValue(); // CasesCollection<BackedEnum::three, BackedEnum::two, BackedEnum::one>
BackedEnum::collect()->sortBy('color'); // CasesCollection<BackedEnum::three, BackedEnum::two, BackedEnum::one>
BackedEnum::collect()->sortDescBy(fn (BackedEnum $case) => $case->color()); // CasesCollection<BackedEnum::one, BackedEnum::two, BackedEnum::three>

📆 更新日志

请参阅 CHANGELOG 以获取有关最近更改的更多信息。

🧪 测试

composer test

💖 贡献

请参阅CONTRIBUTINGCODE_OF_CONDUCT以获取详细信息。

🧯 安全性

如果您发现任何与安全性相关的问题,请通过电子邮件andrea.marco.sartori@gmail.com联系,而不是使用问题跟踪器。

🏅 致谢

⚖️ 许可证

MIT许可证(MIT)。有关更多信息,请参阅许可证文件