Skip to content

Commit

Permalink
☀️
Browse files Browse the repository at this point in the history
  • Loading branch information
akeylimepie committed Jan 24, 2022
1 parent a51bc2c commit 9c46b57
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
php: [ '8.0' ]
php: [ '7.2', '7.3', '7.4', '8.0' ]

steps:
- name: Setup PHP
Expand Down
57 changes: 52 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,57 @@
# package-skeleton
![Packagist Version](https://img.shields.io/packagist/v/hyqo/?style=flat-square)
![Packagist PHP Version Support](https://img.shields.io/packagist/php-v/hyqo/?style=flat-square)
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/hyqo//run-tests?style=flat-square)
# hyqo/enum implementation
![Packagist Version](https://img.shields.io/packagist/v/hyqo/enum?style=flat-square)
![Packagist PHP Version Support](https://img.shields.io/packagist/php-v/hyqo/enum?style=flat-square)
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/hyqo/enum/run-tests?style=flat-square)

Simple Backed Enums implementation for PHP <8.1

## Install

```sh
composer require hyqo/
composer require hyqo/enum
```

This is very similar to real PHP 8.1 Backed Enums: https://www.php.net/manual/en/language.enumerations.backed.php
* `static` method `from($case): self` will take a scalar and return the corresponding Enum Case. If one is not found, it will throw an exception
* `static` method `tryFrom($case): ?self` will take a scalar and return the corresponding Enum Case. If one is not found, it will return `null`
* `static` method `cases(): array` returns a packed array of all defined Cases
* _read-only_ property `value` is the value specified in the definition
* _read-only_ property `name` is the case-sensitive name of the case itself
* Enums may contain methods

But these are not real Enums, so Cases must be defined via public constants

## Usage
```php
use \Hyqo\Enum\Enum;

class Suit extends Enum
{
public const Hearts = 'H';
public const Diamonds = 'D';
public const Clubs = 'C';
public const Spades = 'S';

public function color(): string
{
switch ($this->value) {
case self::Hearts:
case self::Diamonds:
return 'red';
case self::Clubs:
case self::Spades:
return 'black';
}
}
}

Suit::from(Suit::Hearts)->value //H
Suit::from(Suit::Hearts)->name //Hearts
Suit::from(Suit::Hearts)->color() //red

Suit::tryFrom('foo') //null
Suit::from('foo') //throw \Hyqo\Enum\InvalidValueException

Suit::from(Suit::Hearts)->foo //throw \RuntimeException
Suit::from(Suit::Hearts)->value = 'foo' //throw \RuntimeException
```
10 changes: 5 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "hyqo/",
"name": "hyqo/enum",
"description": "",
"keywords": [
],
Expand All @@ -11,19 +11,19 @@
}
],
"require": {
"php": ">=8.0"
"php": ">=7.2 <8.1"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
"phpunit/phpunit": "^8.5"
},
"autoload": {
"psr-4": {
"Hyqo\\": "src"
"Hyqo\\Enum\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Hyqo\\\\Test\\": "tests"
"Hyqo\\Enum\\Test\\": "tests"
}
}
}
7 changes: 0 additions & 7 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
executionOrder="random"
failOnWarning="true"
failOnRisky="true"
failOnEmptyTestSuite="true"
beStrictAboutOutputDuringTests="true"
verbose="true"
>
Expand All @@ -16,10 +15,4 @@
<directory>./tests</directory>
</testsuite>
</testsuites>
<coverage includeUncoveredFiles="false"
ignoreDeprecatedCodeUnits="true">
<include>
<directory suffix=".php">src</directory>
</include>
</coverage>
</phpunit>
88 changes: 88 additions & 0 deletions src/Enum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

namespace Hyqo\Enum;

/**
* @property $value
* @property $name
*/
abstract class Enum
{
protected $value;
protected $name;

/**
* @param string|int $value
*/
public function __construct($value)
{
foreach (self::cases() as $name => $backedValue) {
if ($backedValue === $value) {
$this->value = $value;
$this->name = $name;
return;
}
}

throw new InvalidValueException(sprintf('Invalid value: %s', $value));
}

public static function cases(): array
{
return (new \ReflectionClass(static::class))->getConstants();
}

/**
* @param string|int
* @return static
*/
public static function from($value): self
{
if (!is_scalar($value)) {
throw new \InvalidArgumentException('Only scalar value is available, %s given', gettype($value));
}

return new static($value);
}

/**
* @param string|int
* @return static|null
*/
public static function tryFrom($value): ?self
{
try {
return self::from($value);
} catch (InvalidValueException $e) {
return null;
}
}

final public function __get($name)
{
switch ($name){
case 'value':
return $this->value;
case 'name':
return $this->name;
default:
throw new \RuntimeException('Only "value" and "name" properties can be read');
}
}

final public function __set($name, $value)
{
throw new \RuntimeException('Property does not exist');
}

final public function __isset($name): bool
{
switch ($name){
case 'value':
case 'name':
return true;
default:
return false;
}
}
}
8 changes: 8 additions & 0 deletions src/InvalidValueException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Hyqo\Enum;

class InvalidValueException extends \InvalidArgumentException
{

}
62 changes: 62 additions & 0 deletions tests/EnumTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

namespace Hyqo\Enum\Test;

use Hyqo\Enum\Enum;
use Hyqo\Enum\InvalidValueException;
use PHPUnit\Framework\TestCase;

class EnumTest extends TestCase
{
public function test_create(): void
{
$this->assertEquals('H', Suit::from(Suit::Hearts)->value);
$this->assertEquals('Hearts', Suit::from(Suit::Hearts)->name);

$this->assertNull(Suit::tryFrom('foo'));

$this->expectException(InvalidValueException::class);
Suit::from('foo');
}

public function test_write_value(): void
{
$this->expectException(\RuntimeException::class);
Suit::from(Suit::Hearts)->value = 'foo';
}

public function test_cases(): void
{
$this->assertEquals([
'Hearts' => 'H',
'Diamonds' => 'D',
'Clubs' => 'C',
'Spades' => 'S',
], Suit::cases());
}

public function test_method(): void
{
$this->assertEquals('red', Suit::from(Suit::Hearts)->color());
}
}

class Suit extends Enum
{
public const Hearts = 'H';
public const Diamonds = 'D';
public const Clubs = 'C';
public const Spades = 'S';

public function color(): string
{
switch ($this->value) {
case self::Hearts:
case self::Diamonds:
return 'red';
case self::Clubs:
case self::Spades:
return 'black';
}
}
}

0 comments on commit 9c46b57

Please sign in to comment.