用户名 / enum-helper
简单的、有偏见的、无框架依赖的PHP 8.1枚举助手
Requires
- php: ^8.1
- ext-ctype: *
- ext-mbstring: *
Requires (Dev)
- laravel/pint: ^v1.13
- pestphp/pest: ^1.21
- phpstan/phpstan: ^1.7
README
一个简单的、有偏见的PHP 8.1枚举助手集合,灵感来自 archtechx/enums 和 BenSampo/laravel-enum。
此包无框架依赖,但如果您使用Laravel,建议使用此链接包 suleymanozev/laravel-enum-helper。
功能摘要
- 可调用案例:通过静态调用获取枚举的值
- 通过名称或值构建枚举:`from()`、`tryFrom()`、`fromName()`、`tryFromName()`、`fromValue()`、`tryFromValue()` 方法
- 枚举检查:`isPure()`、`isBacked()`、`has()`、`hasName()`、`hasValue()` 方法
- 枚举相等性:`is()`、`isNot()`、`in()`、`notIn()` 方法
- 名称:获取案例名称列表的方法(`names()`、`namesByValue()`)
- 值:获取案例值列表的方法(`values()`、`valuesByName()`)
- 唯一ID:从实例获取唯一标识符或从标识符获取实例(`uniqueId()`、`fromUniqueId()`)
- 描述 & 翻译:向枚举添加描述(可选翻译)(`description()`、`descriptions()`、`descriptionsByName()`、`descriptionsByValue()`、`nullableDescriptionsByValue()`)
安装
需要PHP 8.1+。
composer require suleymanozev/enum-helper
用法
您可以使用所需的特性,但为了方便,您可以使用包含(`EnumInvokable`、`EnumFroms`、`EnumNames`、`EnumValues`、`EnumInspection`、`EnumEquality`)的`EnumHelper`特性。
`EnumDescription`和`EnumUniqueId`与`EnumHelper`分开,因为它们涵盖了边缘情况。
该助手支持纯枚举(例如`PureEnum`、`PascalCasePureEnum`)和`BackedEnum`(例如`IntBackedEnum`、`StringBackedEnum`)。
在所有示例中,我们将使用下面描述的类
use Suleymanozev\EnumHelper\EnumHelper; // Pure enum enum PureEnum { use EnumHelper; case PENDING; case ACCEPTED; case DISCARDED; case NO_RESPONSE; } enum PascalCasePureEnum { use EnumHelper; case Pending; case Accepted; case Discarded; case NoResponse; } // BackedEnum enum StringBackedEnum: string { use EnumHelper; case PENDING = 'P'; case ACCEPTED = 'A'; case DISCARDED = 'D'; case NO_RESPONSE = 'N'; } enum IntBackedEnum: int { use EnumHelper; case PENDING = 0; case ACCEPTED = 1; case DISCARDED = 2; case NO_RESPONSE = 3; }
该包与以UPPER_CASE、snake_case和PascalCase编写的案例一起工作
跳转至
可调用案例
此助手允许您通过静态调用(`PureEnum::pending()`)和实例调用(`$status()`)来获取`BackedEnum`的值或纯枚举的名称。
一个好的做法是以camelCase模式调用方法,但您可以在所有情况下调用枚举`::STATICALLY()`、`::statically()`或`::Statically()`。
IntBackedEnum::PENDING // PureEnum enum instance IntBackedEnum::pending(); // 0
这样允许您在数组键定义中使用枚举调用
'statuses' => [ PureEnum::pending() => 'some configuration', ...
或在与数据库交互中使用`$db_field_definition->default(PureEnum::pending())`或调用实例以获取原始值
public function updateStatus(int $status): void; $task->updateStatus(IntBackedEnum::pending());
示例使用静态调用获取原始值
// Pure Enum PureEnum::noResponse(); // 'NO_RESPONSE' PureEnum::NO_RESPONSE(); // 'NO_RESPONSE' PureEnum::NoResponse(); // 'NO_RESPONSE' // Pure Enum with PascalCase PascalCasePureEnum::noResponse(); // 'NoResponse' PascalCasePureEnum::NO_RESPONSE(); // 'NoResponse' PascalCasePureEnum::NoResponse(); // 'NoResponse' // IntBackedEnum IntBackedEnum::pending(); // 0 // StringBackedEnum StringBackedEnum::pending(); // 'P'
IDE代码补全
要获得代码补全,您可以在键入枚举案例时获取自动建议,然后添加(),或者您可以在枚举类中添加phpDoc @method标签来定义所有可调用案例,如下所示
/** * @method static string pending() * @method static string accepted() * @method static string discarded() * @method static string noResponse() */ enum PureEnum ...
FromFromName
此辅助函数为纯枚举添加了 from()
和 tryFrom()
,为所有枚举添加了 fromValue()
和 tryFromValue()
(from()
和 tryFrom()
的别名),以及 fromName()
和 tryFromName()
重要提示
BackedEnum
实例已经实现了自己的from()
和tryFrom()
方法,这些方法不会被此特质覆盖。
from()
// Pure Enum PureEnum::from('PENDING'); // PureEnum::PENDING PascalCasePureEnum::from('Pending'); // PascalCasePureEnum::Pending PureEnum::from('MISSING'); // ValueError Exception // BackedEnum StringBackedEnum::from('P'); // StringBackedEnum::PENDING StringBackedEnum::from('M'); // ValueError Exception
tryFrom()
// Pure Enum PureEnum::tryFrom('PENDING'); // PureEnum::PENDING PureEnum::tryFrom('MISSING'); // null // BackedEnum StringBackedEnum::tryFrom('P'); // StringBackedEnum::PENDING StringBackedEnum::tryFrom('M'); // null
fromName()
// Pure Enum PureEnum::fromName('PENDING'); // PureEnum::PENDING PureEnum::fromName('MISSING'); // ValueError Exception // BackedEnum StringBackedEnum::fromName('PENDING'); // StringBackedEnum::PENDING StringBackedEnum::fromName('MISSING'); // ValueError Exception
tryFromName()
// Pure Enum PureEnum::tryFromName('PENDING'); // PureEnum::PENDING PureEnum::tryFromName('MISSING'); // null // BackedEnum StringBackedEnum::tryFromName('PENDING'); // StringBackedEnum::PENDING StringBackedEnum::tryFromName('MISSING'); // null
检查
此辅助函数允许检查枚举的类型(isPure()
、isBacked()
)以及枚举是否包含某个案例名称或值(has()
、doesntHave()
、hasName()
、doesntHaveName()
、hasValue()
、doesntHaveValue()
)。
isPure()
和 isBacked()
使用这些方法可以检查枚举实例的类型。
PureEnum::PENDING->isPure() // true PureEnum::PENDING->isBacked() // false IntBackedEnum::PENDING->isPure() // false StringBackedEnum::PENDING->isBacked() // true
has()
和 doesntHave()
has()
方法允许通过传递整数、字符串或枚举实例来检查枚举是否具有某个案例(名称或值)。为了方便,还有一个 doesntHave()
方法,它是 has()
方法的逆。
PureEnum::has('PENDING') // true IntBackedEnum::has(10) // false IntBackedEnum::has(1) // true IntBackedEnum::has('1') // true StringBackedEnum::has('ACCEPTED') // true StringBackedEnum::has('A') // true StringBackedEnum::doesntHave('A') // false
hasName()
和 doesntHaveName()
hasName()
方法允许检查枚举是否具有某个案例名称。为了方便,还有一个 doesntHaveName()
方法,它是 hasName()
方法的逆。
PureEnum::hasName('PENDING') // true PureEnum::hasName('P') // false IntBackedEnum::hasName('ACCEPTED') // true IntBackedEnum::hasName(1) // false StringBackedEnum::doesntHaveName('ACDSIED') // true StringBackedEnum::hasName('A') // false
hasValue()
和 doesntHaveValue()
hasValue()
方法允许通过传递整数、字符串或枚举实例来检查枚举是否具有某个案例。为了方便,还有一个 doesntHaveValue()
方法,它是 hasValue()
方法的逆。
PureEnum::hasValue('PENDING') // true PureEnum::hasValue('P') // false IntBackedEnum::hasValue('ACCEPTED') // false IntBackedEnum::hasValue(1) // true StringBackedEnum::doesntHaveValue('Z') // true StringBackedEnum::hasValue('A') // true
相等性
此辅助函数允许比较枚举实例(is()
、isNot()
)并搜索它是否存在于数组中(in()
、notIn()
)。
is()
和 isNot()
is()
方法允许检查实例与枚举实例、案例名称或案例值的相等性。
为了方便,还有一个 isNot()
方法,它是 is()
方法的逆。
$enum = PureEnum::PENDING; $enum->is(PureEnum::PENDING); // true PureEnum::PENDING->is(PureEnum::ACCEPTED); // false PureEnum::PENDING->is('PENDING'); // true PureEnum::PENDING->is('ACCEPTED'); // false PureEnum::PENDING->isNot('ACCEPTED'); // true $backedEnum = IntBackedEnum::PENDING; $backedEnum->is(IntBackedEnum::PENDING); // true IntBackedEnum::PENDING->is(IntBackedEnum::ACCEPTED); // false IntBackedEnum::PENDING->is(0); // true IntBackedEnum::PENDING->is('PENDING'); // true StringBackedEnum::PENDING->is('P'); // true StringBackedEnum::PENDING->isNot('P'); // false
in()
和 notIn()
in()
方法允许检查实例是否与实例数组、名称或值匹配。为了方便,还有一个 notIn()
方法,它是 in()
方法的逆。
$enum = PureEnum::PENDING; $enum->in([PureEnum::PENDING,PureEnum::ACCEPTED]); // true PureEnum::PENDING->in([PureEnum::DISCARDED, PureEnum::ACCEPTED]); // false PureEnum::PENDING->in(['PENDING', 'ACCEPTED']); // true PureEnum::PENDING->in(['ACCEPTED', 'DISCARDED']); // false PureEnum::PENDING->notIn(['ACCEPTED']); // true $backedEnum = IntBackedEnum::PENDING; $backedEnum->in([IntBackedEnum::PENDING, IntBackedEnum::ACCEPTED]); // true IntBackedEnum::PENDING->in([IntBackedEnum::ACCEPTED])// false IntBackedEnum::PENDING->in([0, 1, 2]); // true IntBackedEnum::PENDING->in([2, 3]); // false IntBackedEnum::PENDING->in(['PENDING', 'ACCEPTED']); // true IntBackedEnum::PENDING->in(['DISCARDED', 'ACCEPTED']); // false StringBackedEnum::PENDING->in(['P', 'D']); // true StringBackedEnum::PENDING->notIn(['A','D']); // true
名称
此辅助函数提供了 names()
和 namesByValue()
方法。
names()
此方法返回枚举中案例名称的列表。
PureEnum::names(); // ['PENDING', 'ACCEPTED', 'DISCARDED', 'NO_RESPONSE'] PascalCasePureEnum::names(); // ['Pending', 'Accepted', 'Discarded', 'NoResponse'] StringBackedEnum::names(); // ['PENDING', 'ACCEPTED', 'DISCARDED', 'NO_RESPONSE'] // Subset PureEnum::names([PureEnum::NO_RESPONSE, PureEnum::DISCARDED]); // ['NO_RESPONSE', 'DISCARDED'] PascalCasePureEnum::names([PascalCasePureEnum::Accepted, PascalCasePureEnum::Discarded]); // ['Accepted', 'Discarded']
namesByValue()
此方法返回 BackedEnum
上的 [值 => 名称] 关联数组,纯枚举上的 [名称 => 名称] 关联数组。
PureEnum::namesByValue(); // [ 'PENDING' => 'PENDING', 'ACCEPTED' => 'ACCEPTED', 'DISCARDED' => 'DISCARDED'... StringBackedEnum::namesByValue(); // [ 'P' => 'PENDING', 'A' => 'ACCEPTED', 'D' => 'DISCARDED'... IntBackedEnum::namesByValue(); // [ 0=>'PENDING', 1=>'ACCEPTED', 2=>'DISCARDED'... // Subset IntBackedEnum::namesByValue([IntBackedEnum::NO_RESPONSE, IntBackedEnum::DISCARDED]); // [ 3=>'NO_RESPONSE', 2=>'DISCARDED']
值
此辅助函数提供了 values()
和 valuesByName()
方法。
values()
此方法返回 BackedEnum
的案例值列表或纯枚举的案例名称列表。
PureEnum::values(); // ['PENDING', 'ACCEPTED', 'DISCARDED', 'NO_RESPONSE'] StringBackedEnum::values(); // ['P', 'A', 'D', 'N'] IntBackedEnum::values(); // [0, 1, 2, 3] // Subset PureEnum::values([PureEnum::NO_RESPONSE, PureEnum::DISCARDED]); // ['NO_RESPONSE', 'DISCARDED'] StringBackedEnum::values([StringBackedEnum::NO_RESPONSE, StringBackedEnum::DISCARDED]); // ['N', 'D'] IntBackedEnum::values([IntBackedEnum::NO_RESPONSE, IntBackedEnum::DISCARDED]); // [3, 2]
valuesByName()
此方法返回 BackedEnum
上的 [名称 => 值] 关联数组,纯枚举上的 [名称 => 名称] 关联数组。
PureEnum::valuesByName(); // ['PENDING' => 'PENDING','ACCEPTED' => 'ACCEPTED','DISCARDED' => 'DISCARDED',...] StringBackedEnum::valuesByName(); // ['PENDING' => 'P','ACCEPTED' => 'A','DISCARDED' => 'D','NO_RESPONSE' => 'N'] IntBackedEnum::valuesByName(); // ['PENDING' => 0,'ACCEPTED' => 1,'DISCARDED' => 2,'NO_RESPONSE' => 3] // Subset PureEnum::valuesByName([PureEnum::NO_RESPONSE, PureEnum::DISCARDED]); // ['NO_RESPONSE' => 'NO_RESPONSE', 'DISCARDED' => 'DISCARDED'] StringBackedEnum::valuesByName([StringBackedEnum::NO_RESPONSE, StringBackedEnum::DISCARDED]); // ['NO_RESPONSE' => 'N', 'DISCARDED' => 'D'] IntBackedEnum::valuesByName([IntBackedEnum::NO_RESPONSE, IntBackedEnum::DISCARDED]); // ['NO_RESPONSE' => 3, 'DISCARDED' => 2]
唯一标识符
此辅助函数允许从枚举或标识符获取唯一标识符。
此辅助函数不包括在基础 EnumHelper
特质中,也不依赖于它,因此如果您需要它,必须使用 EnumUniqueId
。
use Suleymanozev\EnumHelper\Traits\EnumUniqueId; enum PureEnum { use EnumUniqueId; ...
uniqueId()
此方法返回基于命名空间\类名.CASE_NAME 的枚举唯一标识符。您可以使用此标识符将多种类型的枚举保存到数据库的多态列中。
PureEnum::PENDING->uniqueId(); // Namespace\PureEnum.PENDING $enum = StringBackedEnum::NO_RESPONSE; $enum->uniqueId(); // Namespace\StringBackedEnum.NO_RESPONSE
fromUniqueId()
此方法从唯一标识符返回枚举实例。
PureEnum::fromUniqueId('Namespace\PureEnum.PENDING'); // PureEnum::PENDING IntBackedEnum::fromUniqueId('Namespace\IntBackedEnum.PENDING'); // IntBackedEnum::PENDING IntBackedEnum::fromUniqueId('NOT.valid.uniqueId'); // throw InvalidUniqueId Exception IntBackedEnum::fromUniqueId('Wrong\Namespace\IntBackedEnum.PENDING'); // throw InvalidUniqueId Exception IntBackedEnum::fromUniqueId('Namespace\IntBackedEnum.MISSING'); // throw InvalidUniqueId Exception
全局 getEnumFromUniqueId() 辅助函数
fromUniqueId()
方法使用较少,因为它仅与枚举类相关。更好的方法是创建一个全局辅助函数,可以像这样从 uniqueId 实例化任何枚举
use Suleymanozev\EnumHelper\Exceptions\InvalidUniqueId; public function getEnumFromUniqueId(string $uniqueId): object { if ( !strpos($uniqueId, '.') || substr_count($uniqueId, '.') !== 1 ) { throw InvalidUniqueId::uniqueIdFormatIsInvalid($uniqueId); } list($enumClass, $enumName) = explode('.', $uniqueId); foreach ($enumClass::cases() as $case){ if( $case->name === $enumName){ return $case; } } } throw InvalidUniqueId::caseNotPresent($case); }
描述和翻译
此辅助工具允许为枚举的每个案例提供描述。适用于单语言和多语言应用程序。在需要更好的描述来表征案例或在多语言环境中时,这很有用。
此辅助工具不包括在基本EnumHelper
特质中,也不依赖于它,因此如果您需要它,您必须使用EnumDescription
并实现抽象的description()
方法来定义描述。您可以在纯枚举和BackedEnum
上使用它。
use Suleymanozev\EnumHelper\EnumHelper; use Suleymanozev\EnumHelper\Traits\EnumDescription; enum StringBackedEnum: string { use EnumHelper; use EnumDescription; case PENDING = 'P'; case ACCEPTED = 'A'; case DISCARDED = 'D'; case NO_RESPONSE = 'N'; public function description(?string $lang = null): string { return match ($this) { self::PENDING => 'Await decision', self::ACCEPTED => 'Recognized valid', self::DISCARDED => 'No longer useful', self::NO_RESPONSE => 'No response', }; }
在实现description()
方法之后,您可以
PureEnum::PENDING->description(); // 'Await decision'
本地化
您可以使用自己的翻译方法/辅助工具替换description()
方法来翻译描述。
public function description(?string $lang = null): string { // this is only an example of implementation... translate method not exist // if $lang is null you have to use the current locale return return translate('status.'$this->name, $lang); // or translate each case return match ($this) { self::PENDING => translate('Await decision'), self::ACCEPTED => translate('Recognized valid'), self::DISCARDED => translate('No longer useful'), self::NO_RESPONSE => translate('No response'), }; //or use EnumUniqueId trait return translate($this->uniqueId(), $lang); }
在实现description
方法之后,您可以
$enum = PureEnum::PENDING; $enum->description(); // 'Await decision' $enum->description('it'); // 🇮🇹 'In attesa'
descriptions()
此方法返回枚举案例描述的列表。
StringBackedEnum::descriptions(); // ['Await decision','Recognized valid','No longer useful','No response'] // Subset StringBackedEnum::descriptions([StringBackedEnum::ACCEPTED, StringBackedEnum::NO_RESPONSE]); // ['Recognized valid','No response']
descriptionsByValue()
此方法返回一个关联数组,在BackedEnum
上为[value => description],在纯枚举上为[name => description]。
StringBackedEnum::descriptionsByValue(); // ['P' => 'Await decision', 'A' => 'Recognized valid',... PureEnum::descriptionsByValue(); // ['PENDING' => 'Await decision', 'ACCEPTED' => 'Recognized valid',... // Subset StringBackedEnum::descriptionsByValue([StringBackedEnum::DISCARDED, StringBackedEnum::ACCEPTED]); // ['D' => 'No longer useful', 'A' => 'Recognized valid'] PureEnum::descriptionsByValue([[PureEnum::PENDING, PureEnum::DISCARDED]); // ['PENDING' => 'Await decision', 'DISCARDED' => 'No longer useful']
nullableDescriptionsByValue()
此方法将默认值添加到descriptionsByValue()
的开头,这在您需要在表单上执行可空选择时很有用。
StringBackedEnum::nullableDescriptionsByValue('Select value'); // [null => 'Select value', 'P' => 'Await decision', 'A' => 'Recognized valid',...
特别感谢
- Datomatic 团队