Skip to content

Commit 30754e4

Browse files
committed
initial commit
0 parents  commit 30754e4

File tree

14 files changed

+315
-0
lines changed

14 files changed

+315
-0
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
## ide
2+
.idea
3+
4+
## composer
5+
vendor
6+
composer.lock

README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
Type safe enums
2+
3+
## Getting started
4+
5+
Create enum class
6+
```php
7+
/**
8+
* @method static self ENGLAND()
9+
* @method static self USA()
10+
*/
11+
class CountryEnum
12+
{
13+
protected static function getEnums(): array
14+
{
15+
return ['england', 'usa'];
16+
}
17+
18+
}
19+
```
20+
21+
## Usage
22+
23+
static method must be always uppercase
24+
```php
25+
assert(CountryEnum::USA() === CountryEnum::USA());
26+
27+
function country(CountryEnum $country): string {
28+
return $country->value();
29+
}
30+
31+
assert(country(CountryEnum::USA()) === 'usa');
32+
```
33+
34+
convert enum value to object:
35+
```php
36+
assert(CountryEnum::get('usa') === CountryEnum::USA());
37+
```

codeception.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace: Tests
2+
suites:
3+
unit:
4+
path: .
5+
6+
settings:
7+
shuffle: true
8+
lint: true
9+
paths:
10+
tests: tests
11+
output: tests/_output
12+
support: tests/_support
13+
data: tests
14+

composer.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "warengo/enum",
3+
"type": "library",
4+
"require": {
5+
"php": ">=7.4"
6+
},
7+
"autoload": {
8+
"psr-4": {
9+
"Warengo\\Enum\\": "src/"
10+
}
11+
},
12+
"autoload-dev": {
13+
"psr-4": {
14+
"Warengo\\Tests\\": "tests/src/"
15+
}
16+
},
17+
"require-dev": {
18+
"codeception/codeception": "^4.1",
19+
"codeception/module-phpbrowser": "^1.0.0",
20+
"codeception/module-asserts": "^1.0.0"
21+
}
22+
}

src/Enum.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Warengo\Enum;
4+
5+
abstract class Enum extends EnumStatic
6+
{
7+
8+
private string $value;
9+
10+
final protected function __construct(string $value)
11+
{
12+
$this->value = $value;
13+
}
14+
15+
public function value(): string
16+
{
17+
return $this->value;
18+
}
19+
20+
public function __toString(): string
21+
{
22+
return $this->value;
23+
}
24+
25+
}

src/EnumListInterface.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Warengo\Enum;
4+
5+
interface EnumListInterface
6+
{
7+
8+
public function has(string $name): bool;
9+
10+
public function get(string $name): string;
11+
12+
}

src/EnumStatic.php

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Warengo\Enum;
4+
5+
use Warengo\Enum\Exceptions\InvalidArgumentException;
6+
use Warengo\Enum\Storage\EnumStorage;
7+
8+
/**
9+
* @internal
10+
*/
11+
abstract class EnumStatic
12+
{
13+
14+
/** @var EnumStorage[] */
15+
private static array $storages = [];
16+
17+
/** @var mixed[] */
18+
private static array $lists = [];
19+
20+
/**
21+
* @return string[]
22+
*/
23+
abstract protected static function getEnums(): array;
24+
25+
/**
26+
* @param mixed[] $arguments
27+
*/
28+
final public static function __callStatic(string $name, array $arguments)
29+
{
30+
if ($name !== strtoupper($name)) {
31+
throw new InvalidArgumentException(sprintf('Called static class must be uppercase, %s given', $name));
32+
}
33+
34+
return static::get($name);
35+
}
36+
37+
/**
38+
* @return static
39+
*/
40+
final public static function get(string $name)
41+
{
42+
$name = strtolower($name);
43+
$storage = self::getStorage();
44+
if (!$storage->has($name)) {
45+
if (!isset(self::getEnumsCached()[$name])) {
46+
throw new InvalidArgumentException(
47+
sprintf('Enum %s not exists in %s', strtoupper($name), static::class)
48+
);
49+
}
50+
51+
$storage->set($name, new static($name));
52+
}
53+
54+
return $storage->get($name);
55+
}
56+
57+
/**
58+
* @return string[]
59+
*/
60+
private static function getEnumsCached(): array
61+
{
62+
if (!isset(self::$lists[static::class])) {
63+
foreach (static::getEnums() as $value) {
64+
self::$lists[static::class][$value] = true;
65+
}
66+
}
67+
68+
return self::$lists[static::class];
69+
}
70+
71+
private static function getStorage(): EnumStorage
72+
{
73+
if (!isset(self::$storages[static::class])) {
74+
self::$storages[static::class] = new EnumStorage(static::class);
75+
}
76+
77+
return self::$storages[static::class];
78+
}
79+
80+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Warengo\Enum\Exceptions;
4+
5+
class InvalidArgumentException extends \InvalidArgumentException
6+
{
7+
8+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Warengo\Enum\Exceptions;
4+
5+
use Exception;
6+
7+
class UnexpectedValueException extends Exception
8+
{
9+
10+
}

src/Storage/EnumStorage.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Warengo\Enum\Storage;
4+
5+
use Warengo\Enum\Enum;
6+
use Warengo\Enum\Exceptions\InvalidArgumentException;
7+
use Warengo\Enum\Exceptions\UnexpectedValueException;
8+
9+
class EnumStorage
10+
{
11+
12+
/** @var Enum[] */
13+
private $storage = [];
14+
15+
private string $class;
16+
17+
public function __construct(string $class)
18+
{
19+
$this->class = $class;
20+
}
21+
22+
public function has(string $name): bool
23+
{
24+
return isset($this->storage[$name]);
25+
}
26+
27+
public function get(string $name): Enum
28+
{
29+
if (!isset($this->storage[$name])) {
30+
throw new InvalidArgumentException(sprintf('%s not exists in enum storage', $name));
31+
}
32+
33+
return $this->storage[$name];
34+
}
35+
36+
public function set(string $name, Enum $enum): void
37+
{
38+
if (!$enum instanceof $this->class) {
39+
throw new UnexpectedValueException(
40+
sprintf('Value must be instance of %s, %s given', $this->class, get_class($enum))
41+
);
42+
}
43+
44+
$this->storage[$name] = $enum;
45+
}
46+
47+
}

0 commit comments

Comments
 (0)