-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEnumOf.php
More file actions
78 lines (64 loc) · 2.01 KB
/
EnumOf.php
File metadata and controls
78 lines (64 loc) · 2.01 KB
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
<?php
declare(strict_types=1);
namespace CasParser\Core\Conversion;
use CasParser\Core\Conversion;
use CasParser\Core\Conversion\Contracts\Converter;
/**
* @internal
*/
final class EnumOf implements Converter
{
private readonly string $type;
/** @var array<class-string<\BackedEnum>, self> */
private static array $cache = [];
/**
* @param list<bool|float|int|string|null> $members
* @param class-string<\BackedEnum>|null $class
*/
public function __construct(
private readonly array $members,
private readonly ?string $class = null,
) {
$type = 'NULL';
foreach ($this->members as $member) {
$type = gettype($member);
}
$this->type = $type;
}
/** @param class-string<\BackedEnum> $enum */
public static function fromBackedEnum(string $enum): self
{
// @phpstan-ignore-next-line argument.type
return self::$cache[$enum] ??= new self(
array_column($enum::cases(), column_key: 'value'),
class: $enum,
);
}
public function coerce(mixed $value, CoerceState $state): mixed
{
$this->tally($value, state: $state);
if ($value instanceof \BackedEnum) {
return $value;
}
if (null !== $this->class && (is_int($value) || is_string($value))) {
return ($this->class)::tryFrom($value) ?? $value;
}
return $value;
}
public function dump(mixed $value, DumpState $state): mixed
{
$this->tally($value, state: $state);
return Conversion::dump_unknown($value, state: $state);
}
private function tally(mixed $value, CoerceState|DumpState $state): void
{
$needle = $value instanceof \BackedEnum ? $value->value : $value;
if (in_array($needle, haystack: $this->members, strict: true)) {
++$state->yes;
} elseif ($this->type === gettype($needle)) {
++$state->maybe;
} else {
++$state->no;
}
}
}