datomatic / enum-helper
简单的、有观点的、无框架的PHP 8.1 枚举辅助框架
Requires
- php: ^8.1
- ext-ctype: *
- ext-mbstring: *
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.8
- pestphp/pest: ^1.21
- phpstan/phpstan: ^1.7
README
枚举辅助
受archtechx/enums和BenSampo/laravel-enum启发的简单且具有观点的PHP 8.1 枚举辅助集合。
此包无框架限制,但如果您使用Laravel,请考虑使用此链接包datomatic/laravel-enum-helper和datomatic/laravel-enum-collections。
功能摘要
- 可调用案例:通过静态方式调用枚举以获取其值
- 按名称或值构造枚举:
from()
、tryFrom()
、fromName()
、tryFromName()
、fromValue()
、tryFromValue()
方法 - 枚举检查:
isPure()
、isBacked()
、has()
、hasName()
、hasValue()
方法 - 枚举等价:
is()
、isNot()
、in()
、notIn()
方法 - 名称:获取案例名称列表的方法(
names()
、namesByValue()
) - 值:获取案例值列表的方法(
values()
、valuesByName()
) - 唯一ID:从实例或ID获取实例(
uniqueId()
、fromUniqueId()
) - 描述和翻译:向枚举添加描述(可选翻译)(
description()
、descriptions()
、descriptionsByName()
、descriptionsByValue()
、nullableDescriptionsByValue()
)
安装
需要PHP 8.1以上。
composer require datomatic/enum-helper
用法
您可以使用所需的特性,但为了方便起见,您可以使用包含(EnumInvokable
、EnumFroms
、EnumNames
、EnumValues
、EnumInspection
、EnumEquality
)的EnumHelper
特性。
EnumDescription
和EnumUniqueId
已从EnumHelper
中分离,因为它们涵盖了边缘情况。
此辅助程序支持纯枚举(例如PureEnum
、PascalCasePureEnum
)和BackedEnum
(例如IntBackedEnum
、StringBackedEnum
)。
以下所有示例都将使用以下描述的类
use Datomatic\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 ...
从FromName
此助手为纯枚举添加了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()
,isIntBacked()
和isStringBacked()
使用这些方法可以检查枚举实例的类型。
PureEnum::PENDING->isPure() // true PureEnum::PENDING->isBacked() // false IntBackedEnum::PENDING->isPure() // false IntBackedEnum::PENDING->isIntBacked() // true StringBackedEnum::PENDING->isBacked() // true StringBackedEnum::PENDING->isStringBacked() // 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
的关联数组[value => name],基于纯枚举的[name => name]。
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
的关联数组[name => value],基于纯枚举的[name => name]。
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 Datomatic\EnumHelper\Traits\EnumUniqueId; enum PureEnum { use EnumUniqueId; ...
uniqueId()
此方法返回基于Namespace\ClassName.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 Datomatic\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 Datomatic\EnumHelper\EnumHelper; use Datomatic\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
上返回一个[值=>描述]的关联数组,在纯枚举上返回[name=>描述]。
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',...