dnl-blkv / simple-php-enum
A simple C/C++ alike enum library.
Requires
- php: >=7.0
Requires (Dev)
- phpunit/phpunit: ^5.4
README
Description
A simple C/C++ alike PHP library for Enums.
Stats and Health
PHP Version Support
The package is new and thus only supports PHP >=7.0
.
How To Basic
Installation
- Install composer
- Open your project folder in terminal
- Enter
composer require dnl-blkv/simple-php-enum
- Wait for the composer to finish the job
- Now, you can start using the Simple PHP Enums as described below!
Defining Enums
Defining a basic Enum with the package is straightforward:
use dnl_blkv\enum\AbstractEnum;
/**
* @method static static CAT()
* @method static static DOG()
* @method static static BIRD()
* @method static static FISH()
*/
class AnimalEnum extends AbstractEnum
{
const CAT = null;
const DOG = null;
const BIRD = null;
const FISH = null;
}
Here null
means auto-determined ordinal value, or auto-ordinal. The default auto-ordinal is 0
. The further auto-ordinal values are determined as {previous ordinal} + 1
.
Enum constant names MUST be PSR-1-compliant AND start from a capital letter. If a constant name does not conform with the rules, the constant is ignored.
Creating
Once the class is defined, the enums can be acquired as:
$animal = AnimalEnum::CAT();
Or:
$animal = AnimalEnum::getByName('CAT');
Or:
$animal = AnimalEnum::getByOrdinal(0);
In the examples above, if the name or the ordinal is not defined, exceptions will be thrown (UndefinedEnumNameException
and UndefinedEnumOrdinalException
correspondingly).
Accessing
You can access the name (string representation) and the ordinal (numeric representation) of the enum:
echo $animal->getName() . ' ' . $animal->getOrdinal(); // Outputs "CAT 0"
Comparison
Equality
The enums can be checked for equality as such:
$cat = AnimalEnum::CAT();
$otherCat = AnimalEnum::CAT();
$dog = AnimalEnum::DOG();
var_dump($cat->isEqual($otherCat)) // Outputs "bool(true)"
var_dump($cat->isEqual($dog)) // Outputs "bool(false)"
Intuitively, two enums of different types are never equal. If we have an enum of type SomeOtherEnum
with const VALUE = 0;
then the following holds:
var_dump(SomeOtherEnum::VALUE()->isEqual(AnimalEnum::CAT())) // Outputs "bool(false)"
Comparison by Ordinal
It is also possible to compare the Simple PHP Enums by their ordinal values. There are four methods defined for this, as shown below:
/**
* @method static static READ()
* @method static static WRITE()
* @method static static ADMIN()
*/
class AccessLevelEnum extends Enum
{
const READ = null;
const WRITE = null;
const ADMIN = null;
}
var_dump(AccessLevelEnum::READ()->isLess(AccessLevelEnum::WRITE())) . PHP_EOL // -> "bool(true)"
var_dump(AccessLevelEnum::READ()->isGreater(AccessLevelEnum::WRITE())) . PHP_EOL // -> "bool(false)"
var_dump(AccessLevelEnum::READ()->isGreaterOrEqual(AccessLevelEnum::READ())) . PHP_EOL // -> "bool(true)"
var_dump(AccessLevelEnum::READ()->isLessOrEqual(AccessLevelEnum::ADMIN())) . PHP_EOL // -> "bool(true)"
If two enums of different types are compared, the InvalidArgumentException
is thrown.
How To Advanced
Defining Enums with Custom Ordinals
Besides letting the library assign the ordinals automatically, you could manually assign custom integer values to the ordinals:
use dnl_blkv\enum\AbstractEnum;
/**
* @method static static PIZZA()
* @method static static SUSHI()
* @method static static KEBAB()
* @method static static SALAD()
*/
class FoodEnum extends AbstractEnum
{
const PIZZA = 5;
const SUSHI = null;
const KEBAB = 8;
const SALAD = 10;
}
In this case the enums will be defined as following:
echo FoodEnum::PIZZA()->getOrdinal() . PHP_EOL; // Outputs "5"
echo FoodEnum::SUSHI()->getOrdinal() . PHP_EOL; // Outputs "6"
echo FoodEnum::KEBAB()->getOrdinal() . PHP_EOL; // Outputs "8"
echo FoodEnum::SALAD()->getOrdinal() . PHP_EOL; // Outputs "10"
Duplicate Ordinals
Similarly to the vanilla C/C++ enums, this Simple PHP Enums allow for duplicate ordinals. This may be used for tackling such cases as a default value:
use dnl_blkv\enum\AbstractEnum;
/**
* @method static static LAGER()
* @method static static IPA()
* @method static static PORTER()
* @method static static STOUT()
* @method static static DEFAULT()
* @method static static AFTER_DEFAULT()
*/
class BeerEnum extends AbstractEnum
{
const LAGER = 0;
const IPA = null;
const PORTER = null;
const STOUT = null;
const DEFAULT = 0;
const AFTER_DEFAULT = null;
}
For the enum defined above, the following will hold:
echo BeerEnum::DEFAULT()->getOrdinal() . PHP_EOL; // Outputs "0"
echo BeerEnum::AFTER_DEFAULT()->getOrdinal() . PHP_EOL; // Outputs "1"
If you are getting an enum with duplicate ordinal using a magic method or by name, it works as usual.
echo BeerEnum::DEFAULT()->getName() . PHP_EOL; // Outputs "DEFAULT"
echo BeerEnum::getByName('DEFAULT')->getName() . PHP_EOL; // Outputs "DEFAULT"
However, if you get it by an ordinal, the behavior is slightly different, and you have two options as shown below:
echo BeerEnum::getFirstByOrdinal(0)->getName() . PHP_EOL; // Outputs "LAGER"
$allEnumWithOrdinalZero = BeerEnum::getAllByOrdinal(0);
echo $allEnumWithOrdinalZero[0]->getName() . PHP_EOL; // Outputs "LAGER"
echo $allEnumWithOrdinalZero[1]->getName() . PHP_EOL; // Outputs "DEFAULT"
More Equality
The Simple PHP Enum library only creates each enum object once and then reuses it. Therefore, the enums are comparable with ===
or its alias isSame
. This kind comparison is stricter than isEqual
. Whereas isEqual
only accounts for the enum type and ordinal, isSame
also takes the name
into account:
var_dump(BeerEnum::LAGER()->isEqual(BeerEnum::LAGER())); // Outputs "bool(true)"
var_dump(BeerEnum::LAGER()->isEqual(BeerEnum::DEFAULT())); // Outputs "bool(true)"
var_dump(BeerEnum::LAGER() === BeerEnum::LAGER()); // Outputs "bool(true)"
var_dump(BeerEnum::LAGER() === BeerEnum::DEFAULT()); // Outputs "bool(false)"
var_dump(BeerEnum::LAGER()->isSame(BeerEnum::LAGER())); // Outputs "bool(true)"
var_dump(BeerEnum::LAGER()->isSame(BeerEnum::DEFAULT())); // Outputs "bool(false)"
Checking Existence of Names and Ordinals
If you wish to check whether or not certain enum type has a given name or ordinal, there are methods allowing you to easily do so:
var_dump(BeerEnum::isNameDefined('STOUT')) // Outputs "bool(true)";
var_dump(BeerEnum::isNameDefined('VODKA')) // Outputs "bool(false)";
var_dump(BeerEnum::isOrdinalDefined(3)) // Outputs "bool(true)";
var_dump(BeerEnum::isOrdinalDefined(420)) // Outputs "bool(false)";
Converting to String
The enums have an embedded magical mechanism for serialization:
echo BeerEnum::IPA() . PHP_EOL;
/*
* Outputs:
* {
* "\your\name\space\BeerEnum": {
* "name": "IPA",
* "ordinal": 1
* }
* }
*/
Notes
Extension
All the internals of the AbstractEnum
class are either public
or protected
. Therefore, it is completely open for extension and allows you to build your own, more complex constructions on top of it.
Use with Databases
If you opt to use these enums with databases and store the ordinals, I would recommend to make sure that no stored enum has duplicate ordinals. Otherwise, it could happen that you store DEFAULT = 0
, but receive IPA = 0
upon recreation.