Completed
Push — master ( 160cf4...7f7ab9 )
by Maxime
11s
created

Enum::get()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 7
cts 7
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 3
nop 1
crap 3
1
<?php
2
3
/*
4
 * This file is part of the "elao/enum" package.
5
 *
6
 * Copyright (C) 2016 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
abstract class Enum implements EnumInterface
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 9
    final private function __construct($value)
36
    {
37 9
        $this->value = $value;
38
39 9
        $enumType = static::class;
40 9
        $identifier = serialize($value);
41
42 9
        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 9
        if (!isset(self::$instances[$enumType])) {
49 3
            self::$instances[$enumType] = [];
50
        }
51
52 9
        self::$instances[$enumType][$identifier] = $this;
53 9
    }
54
55
    /**
56
     * {@inheritdoc}
57
     *
58
     * @return static The enum instance for given value
59
     */
60 69
    public static function get($value): EnumInterface
61
    {
62 69
        // Return the cached instance for given value if it already exists:
63 69
        if (null !== $instance = self::getCachedInstance($value)) {
64
            return $instance;
65
        }
66 69
67 64
        if (!static::accepts($value)) {
68
            throw new InvalidValueException($value, static::class);
69
        }
70 13
71 3
        return new static($value);
72
    }
73
74 9
    /**
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
        $value = @constant('static::' . $name);
87 2
        if (null === $value) {
88
            throw new \BadMethodCallException(sprintf(
89 2
                'No constant named "%s" exists in class "%s"',
90 2
                $name,
91 1
                static::class
92 1
            ));
93
        }
94 1
95
        return static::get($value);
96
    }
97
98 1
    /**
99
     * {@inheritdoc}
100
     */
101
    public static function accepts($value): bool
102
    {
103
        return in_array($value, static::values(), true);
104 19
    }
105
106 19
    /**
107
     * {@inheritdoc}
108
     */
109
    public static function instances(): array
110
    {
111
        return array_map(function ($value) {
112
            return static::get($value);
113
        }, static::values());
114 19
    }
115 19
116 19
    private static function getCachedInstance($value)
117
    {
118
        $enumType = static::class;
119
        $identifier = serialize($value);
120
121
        if (isset(self::$instances[$enumType][$identifier])) {
122 40
            return self::$instances[$enumType][$identifier];
123
        }
124 40
125
        return null;
126
    }
127
128
    /**
129
     * {@inheritdoc}
130 2
     */
131
    public function getValue()
132 2
    {
133
        return $this->value;
134
    }
135
136
    /**
137
     * {@inheritdoc}
138 3
     */
139
    public function equals(EnumInterface $enum): bool
140 3
    {
141
        return get_class($this) === get_class($enum) && $this->value === $enum->getValue();
142
    }
143
144
    /**
145
     * {@inheritdoc}
146
     */
147
    public function is($value): bool
148
    {
149
        return $this->getValue() === $value;
150
    }
151
}
152