Completed
Pull Request — master (#94)
by Mathieu
01:29
created

EnumTrait::getValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
/*
4
 * This file is part of the "elao/enum" package.
5
 *
6
 * Copyright (C) Elao
7
 *
8
 * @author Elao <[email protected]>
9
 */
10
11
namespace Elao\Enum;
12
13
use Elao\Enum\Exception\InvalidValueException;
14
use Elao\Enum\Exception\LogicException;
15
16
trait EnumTrait
17
{
18
    /**
19
     * Cached array of enum instances by enum type (FQCN).
20
     * This cache is used in order to make single enums values act as singletons.
21
     * This means you'll always get the exact same instance for a same enum value.
22
     *
23
     * @var array
24
     */
25
    private static $instances;
26
27
    /** @var mixed */
28
    protected $value;
29
30
    /**
31
     * The constructor is private and cannot be overridden: use the static get method instead.
32
     *
33
     * @param mixed $value The raw value of an enumeration
34
     */
35
    final private function __construct($value)
36
    {
37
        $this->value = $value;
38
39
        $enumType = static::class;
40
        $identifier = serialize($value);
41
42
        if (isset(self::$instances[$enumType][$identifier])) {
43
            throw new LogicException(
44
                '"__construct" should not be called when an instance already exists for this enum value.'
45
            );
46
        }
47
48
        if (!isset(self::$instances[$enumType])) {
49
            self::$instances[$enumType] = [];
50
        }
51
52
        self::$instances[$enumType][$identifier] = $this;
53
    }
54
55
    /**
56
     * {@inheritdoc}
57
     *
58
     * @return static The enum instance for given value
59
     */
60
    public static function get($value): EnumInterface
61
    {
62
        // Return the cached instance for given value if it already exists:
63
        if (null !== $instance = self::getCachedInstance($value)) {
64
            return $instance;
65
        }
66
67
        if (!static::accepts($value)) {
68
            throw new InvalidValueException($value, static::class);
69
        }
70
71
        return new static($value);
72
    }
73
74
    /**
75
     * Instantiates a new enumeration.
76
     *
77
     * @param string $name      The name of a particular enumerated constant
78
     * @param array  $arguments
79
     *
80
     * @throws \BadMethodCallException On invalid constant name
81
     *
82
     * @return static When $name is an existing constant for this enumeration type
83
     */
84
    public static function __callStatic($name, $arguments = []): EnumInterface
85
    {
86
        if (!\defined('static::' . $name)) {
87
            throw new \BadMethodCallException(sprintf(
88
                'No constant named "%s" exists in class "%s"',
89
                $name,
90
                static::class
91
            ));
92
        }
93
94
        return static::get(\constant('static::' . $name));
95
    }
96
97
    /**
98
     * {@inheritdoc}
99
     */
100
    public static function accepts($value): bool
101
    {
102
        return \in_array($value, static::values(), true);
103
    }
104
105
    /**
106
     * {@inheritdoc}
107
     */
108
    public static function instances(): array
109
    {
110
        return array_map(static function ($value) {
111
            return static::get($value);
112
        }, static::values());
113
    }
114
115
    private static function getCachedInstance($value)
116
    {
117
        $enumType = static::class;
118
        $identifier = serialize($value);
119
120
        return self::$instances[$enumType][$identifier] ?? null;
121
    }
122
123
    /**
124
     * {@inheritdoc}
125
     */
126
    public function getValue()
127
    {
128
        return $this->value;
129
    }
130
131
    /**
132
     * {@inheritdoc}
133
     */
134
    public function equals(EnumInterface $enum): bool
135
    {
136
        return \get_class($this) === \get_class($enum) && $this->value === $enum->getValue();
137
    }
138
139
    /**
140
     * {@inheritdoc}
141
     */
142
    public function is($value): bool
143
    {
144
        return $this->getValue() === $value;
145
    }
146
}
147