forked from Elao/PhpEnums
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathReadableEnumTrait.php
140 lines (117 loc) · 4.1 KB
/
ReadableEnumTrait.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<?php
declare(strict_types=1);
/*
* This file is part of the "elao/enum" package.
*
* Copyright (C) Elao
*
* @author Elao <[email protected]>
*/
namespace Elao\Enum;
use Elao\Enum\Attribute\EnumCase;
use Elao\Enum\Exception\LogicException;
use Elao\Enum\Exception\NameException;
trait ReadableEnumTrait
{
use EnumCaseAttributesTrait;
/**
* {@inheritdoc}
*/
public static function readableForValue(string|int $value): string
{
if (!is_a(static::class, \BackedEnum::class, true)) {
throw new \BadMethodCallException(sprintf(
'Cannot call method "%s" on non-backed enum "%s".',
__METHOD__,
static::class,
));
}
/** @var ReadableEnumInterface $case */
$case = static::from($value);
return $case->getReadable();
}
/**
* {@inheritdoc}
*/
public static function readableForName(string $name): string
{
/** @var array<string,ReadableEnumInterface>|null $map */
static $map;
if (null === $map) {
$map = array_combine(array_map(static fn (\UnitEnum $e) => $e->name, static::cases()), static::cases());
}
if (!isset($map[$name])) {
throw new NameException($name, static::class);
}
return ($map[$name])->getReadable();
}
/**
* {@inheritdoc}
*/
public function getReadable(): string
{
return static::arrayAccessReadables()[$this];
}
/**
* {@inheritdoc}
*
* Implements readables using PHP 8 attributes, expecting an {@link EnumCase} on each case, with a label.
*/
public static function readables(): iterable
{
static $readables;
if (!isset($readables)) {
$readables = new \SplObjectStorage();
/** @var static $case */
foreach (static::cases() as $case) {
$attribute = $case->getEnumCaseAttribute();
if (null === $attribute) {
throw new LogicException(sprintf(
'enum "%s" using the "%s" trait must define a "%s" attribute on every cases. Case "%s" is missing one. Alternatively, override the "%s()" method',
static::class,
ReadableEnumTrait::class,
EnumCase::class,
$case->name,
__METHOD__,
));
}
if (null === $attribute->label) {
throw new LogicException(sprintf(
'enum "%s" using the "%s" trait must define a label using the "%s" attribute on every cases. Case "%s" is missing a label. Alternatively, override the "%s()" method',
static::class,
ReadableEnumTrait::class,
EnumCase::class,
$case->name,
__METHOD__,
));
}
$readables[$case] = $attribute->label;
}
}
/** @var static $case */
foreach (static::cases() as $case) {
yield $case => $readables[$case];
}
}
/**
* As objects, {@link https://wiki.php.net/rfc/enumerations#splobjectstorage_and_weakmaps Enum cases cannot be used as keys in an array}.
* However, they can be used as keys in a SplObjectStorage or WeakMap.
* Because they are singletons they never get garbage collected, and thus will never be removed from a WeakMap,
* making these two storage mechanisms effectively equivalent.
*
* However, there is a {@link https://wiki.php.net/rfc/object_keys_in_arrays pending RFC} regarding object as array keys.
*
* @internal
*/
private static function arrayAccessReadables(): \SplObjectStorage
{
static $readables;
if (!isset($readables)) {
$readables = new \SplObjectStorage();
foreach (static::readables() as $case => $label) {
$readables[$case] = $label;
}
}
return $readables;
}
}