Earlier this week I released a new package on Packagist. It’s a Package to work with Enumerations in PHP, named bramus/enumeration
. The package is my own take on Enumerations in PHP, which grew over time.
π¨βπ» Looking back at the code that eventually would form the basis for this package, I can see β thanks to Git β that I started working on it back in 2013 (π±). Back then PHP Enumeration packages were still sparse, unlike now.
The first implementation basically was a straight copy from this simple Enum
class I had then found on StackOverflow. It’s only about a year ago though β when I started working on a new project, that makes heavy use of enumerations β that I started adding new features such as making enumerations instantiable, composed enumerations support, etc.
~
When first looking at a class built upon bramus/enumeration
, you can see that it’s quite similar to other implementations (they, after all, all allow you to use enums)
<?php
use Bramus\Enumeration\Enumeration;
class Weekday extends Enumeration
{
const MONDAY = 1;
const TUESDAY = 2;
const WEDNESDAY = 3;
const THURSDAY = 4;
const FRIDAY = 5;
const SATURDAY = 6;
const SUNDAY = 7;
}
When using the Weekday
enumeration shown above, the package starts to differ from some other packages, as bramus/enumeration
provides you with several methods to creating enumerations.
Next to directly accessing a value through the class constant’s identifier it’s also possible to instantiate a bramus/enumeration
, either through its constructor or by calling a static function that holds the name of the identifier (thanks __callStatic()
!).
Weekday::MONDAY
// ~> 1
$instance = new Weekday(1);
$instance = new Weekday(Weekday::MONDAY);
$instance = Weekday::MONDAY(); // <- this is the preferred way to working with bramus/enumeration
π‘ TIP: By allowing one to create instances of a Enumeration
-extended class, you can type hint your enumerations when used as function arguments π
After having created an instance of a bramus/enumeration
class, you can access its data using some logically named accessors:
$instance->getValue();
// ~> 1
$instance->getIdentifier();
// ~> 'MONDAY'
And thanks to its __toString()
implementation you can easily pass these instances into query builders and the like, the value will automatically be returned (as a string
)
(string) $instance;
// ~> '1'
~
Each class that builds upon bramus/enumeration
also has some static functions for:
-
Converting between values and identifiers:
Weekday::toValue('MONDAY'); // ~> 1 Weekday::toIdentifier(1); // ~> 'MONDAY;
-
Listing values and identifiers:
Weekday::values(); // ~> [1, 2, 3, 4, 5, 6, 7] Weekday::identifiers(); // ~> ['MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY']
-
Validating values and identifiers:
Weekday::isValidValue(2); // ~> true Weekday::isValidValue(8); // ~> false Weekday::isValidIdentifier('TUESDAY'); // ~> true Weekday::isValidIdentifier('SUMMERDAY'); // ~> false
~
If you want, you can define a default value to use for a bramus/enumeration
. To achieve this, define it as a constant named __DEFAULT
on your class and you’re good to go:
<?php
use Bramus\Enumeration\Enumeration;
class Weekday extends Enumeration
{
const __DEFAULT = 1;
const MONDAY = 1;
const TUESDAY = 2;
…
}
$instance = new Weekday();
// object(Weekday)#424 (2) {
// ["value":"Bramus\Enumeration\Enumeration":private]=>
// int(1)
// ["identifier":"Bramus\Enumeration\Enumeration":private]=>
// string(6) "MONDAY"
//}
~
Where bramus/enumeration
differs from almost all other enumeration packages, is the fact that it also allows one to create Composed Enumerations. These are enumerations that are composed of other enumerations.
A typical example would be the implementation for HTTP Status Codes. Since they are defined in groups, it would be logical to also implement ‘m that way, and then to combine ‘m.
<?php
namespace Bramus\Http\StatusCodes;
use Bramus\Enumeration\Enumeration;
use Bramus\Enumeration\ComposedEnumeration;
abstract class Informational extends Enumeration
{
const CONTINUE = 100;
const SWITCHING_PROTOCOLS = 101;
const PROCESSING = 102;
}
abstract class Success extends Enumeration
{
const OK = 200;
const CREATED = 201;
const ACCEPTED = 202;
…
}
abstract class Redirection extends Enumeration
{
const MULTIPLE_CHOICES = 300;
const MOVED_PERMANENTLY = 301;
const FOUND = 302;
…
}
abstract class ClientError extends Enumeration
{
const BAD_REQUEST = 400;
const UNAUTHORIZED = 401;
const PAYMENT_REQUIRED = 402;
…
const IM_A_TEAPOT = 418;
…
}
abstract class ServerError extends Enumeration
{
const INTERNAL_SERVER_ERROR = 500;
const NOT_IMPLEMENTED = 501;
const BAD_GATEWAY = 502;
…
const NETWORK_AUTHENTICATION_REQUIRED = 511;
}
class StatusCode extends ComposedEnumeration
{
public static $classes = [
'\Bramus\Http\StatusCodes\Informational',
'\Bramus\Http\StatusCodes\Success',
'\Bramus\Http\StatusCodes\Redirection',
'\Bramus\Http\StatusCodes\ClientError',
'\Bramus\Http\StatusCodes\ServerError',
];
}
β οΈ Due to PHP not having something like __getStatic()
you cannot access constants directly on Composed Enumerations. You must use the direct value in the constructor to create instances when working with Composed Enumerations.
use Bramus\Http\StatusCodes\StatusCode;
// $instance = new StatusCode(StatusCode::OK); <-- This won't work,
$instance = new StatusCode(200);
Due to this limitation, the __callStatic()
method to creating instances is recommended, as it works on both singular as composed enumerations:
$instance = StatusCode::OK();
π‘ If PHP were to support __getStatic()
, I would be able to reroute the request to the correct constant on any of the contained classes and return the correct result β¦Β but that’s unfortunately not the case right now.
Default values also work with Composed Enumerations:
class StatusCode extends ComposedEnumeration
{
const __DEFAULT = 200;
public static $classes = [
β¦
];
}
~
Also shipping with bramus/enumeration
are two utility classes. Whilst you most likely don’t need to use these directly, they might be of help:
-
\Bramus\Enumeration\Helpers\Extractor
This class extracts constants/identifiers/values from enumerations. It is used by
\Bramus\Enumeration\Enumeration
internally. -
\Bramus\Enumeration\Helpers\Generator
This class allows one to generate instances of enumerations. Given the example
\Bramus\Http\StatusCodes\StatusCode
class from above, its usage might be something like this:use Bramus\Enumeration\Helpers\Generator; Generator::setNamespace('\\Bramus\\Http\\StatusCodes\\'); Generator::generateStatusCode(); // Generates a \Bramus\Http\StatusCodes\StatusCode instance with its default value Generator::generateStatusCode(404); // Generates a \Bramus\Http\StatusCodes\StatusCode instance with the value 404
This class might come in handy during unit tests.
πββοΈ In case the Enumeration has no
__DEFAULT
(e.g. it isNULL
), callingGenerator::generate*
will return a random value for the Enumeration.
~
Feel free to use this package if you think it will float your boat. If you’ve find an issue, have a feature request, or something else regarding this project, then please open an issue on its GitHub repo.
bramus/enumeration
Source (GitHub) →
bramus/enumeration
on Packagist →
Thank me with a coffee.
I don\'t do this for profit but a small one-time donation would surely put a smile on my face. Thanks!
To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.
Neat. Tip: s/Informal/Informational/ on the HTTP status groups example.
Whoops β¦ fixed!
And thanks! π