使用php8的注解,方便地定义枚举及其描述
参考了博客:laravel的枚举助手——基于php8.1的枚举特性 ,这篇文章中使用的enum类型,因为enum不能包含属性,我希望能保存map,所以用class+const实现
定义
<?php
namespace App\Enums;
/**
* 方便ide提示,可省略
* @method static string Yes()
* @method static string No()
*/
class YesNo {
use Enum;
#[Description('是')]
const Yes = 1;
#[Description('否')]
const No = 0;
}
使用
class Controller extends BaseController {
public function test() {
dump(YesNo::map());
dump(YesNo::arrayMap());
dump(YesNo::names());
dump(YesNo::values());
dump(YesNo::descriptions());
dump(YesNo::Yes());
dump(YesNo::description(YesNo::No));
dump(YesNo::value('否'));
dump(ConsumableType::make([
'name' => 'test',
'status' => YesNo::Yes,
])->toArray());
}
}
class ConsumableType extends Model {
protected $appends=['status_name'];
protected function statusName(): Attribute {
return Attribute::make(
fn ($value,$attributes) => YesNo::description($attributes['status']),
);
}
}
实现
<?php
namespace App\Enums;
use Attribute;
#[Attribute]
class Description {
public function __construct(string $description) {}
}
<?php
namespace App\Enums;
use Exception;
use Illuminate\Support\Collection;
use ReflectionClass;
/**
* @method static string|null description(int|string $value) 根据值获取描述
* @method static string|null value(string $description) 根据描述获取值
* @method static Collection map() 获取常量值与描述的映射集合
* @method static array arrayMap() 获取常量值与描述的映射数组
* @method static Collection names() 获取常量名集合
* @method static Collection values() 获取常量值集合
* @method static Collection descriptions() 获取描述集合
*/
trait Enum {
public static ?Collection $valueMap = null; // [常量值=>描述]
public static ?Collection $nameMap = null; // [常量名=>描述]
public static ?Collection $descriptionMap = null; // [描述=>常量值]
public static function init(): void {
// 仅执行一次
if (!is_null(static::$valueMap)) {
return;
}
// 获取类的常量反射
$reflection = new ReflectionClass(static::class);
$consts = $reflection->getReflectionConstants();
static::$valueMap = new Collection();
static::$nameMap = new Collection();
foreach ($consts as $const) {
// 获取常量的Description注解
$annotations = $const->getAttributes(Description::class);
if (!empty($annotations)) {
$description = $annotations[0]->getArguments()[0];
// 常量值=>描述 和 常量名=>描述
static::$valueMap->put($const->getValue(), $description);
static::$nameMap->put($const->getName(), $description);
}
}
}
/**
* 根据常量名获取描述
*/
public static function descriptionByName(string $name): ?string {
static::init();
if (static::$nameMap->offsetExists($name)) {
return static::$nameMap->get($name);
}
return null;
}
private static function validateArguments(string $name, array $arguments): void {
switch ($name) {
case 'description':
case 'value':
count($arguments) === 0 && throw new Exception($name . '方法必须传入1个参数');
}
}
/**
* @throws Exception
*/
public static function __callStatic(string $name, array $arguments) {
static::validateArguments($name, $arguments);
static::init();
$name === 'value' && is_null(static::$descriptionMap) && static::$descriptionMap = static::$valueMap->flip();
return match ($name) {
'description' => static::$valueMap->get($arguments[0]),
'value' => static::$descriptionMap->get($arguments[0]),
'map' => static::$valueMap,
'arrayMap' => static::$valueMap->toArray(),
'names' => static::$nameMap->keys(),
'values' => static::$valueMap->keys(),
'descriptions' => static::$valueMap->values(),
default => static::descriptionByName($name), // 常量名作为静态方法调用,返回描述
};
}
}
只做了枚举的简单功能,后续可以完善一下,结合响应状态码,请求验证等,用的时候use Enum就可以了。
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: