Skip to content

Compatibility layer for emulating enumerations in PHP < 8.1 and use native enumerations in PHP >= 8.1

License

Notifications You must be signed in to change notification settings

marc-mabe/php-enum-cl

Repository files navigation

Compatibility layer for emulating enumerations in PHP < 8.1 but native enumerations in PHP >= 8.1

Build Status Code Coverage

How-to create

Vendor\MyEnum.php

<?php declare(strict_types=1);

if (PHP_VERSION_ID < 80100) {
    require_once __DIR__ . '/MyEnum-emulated.php';
} else {
    require_once __DIR__ . '/MyEnum-native.php';
}

Vendor\MyEnum-emulated.php

<?php declare(strict_types=1);

namespace Vendor;

use Mabe\Enum\Cl\EmulatedIntEnum;

final class MyEnum extends EmulatedIntEnum
{
    protected const ZERO = 0;
    protected const ONE = 1;
    protected const TWO = 2;
    protected const THREE = 3;
    protected const FOUR = 4;
    protected const FIVE = 5;
    protected const SIX = 6;
    protected const SEVEN = 7;
    protected const EIGHT = 8;
    protected const NINE = 9;
}

Vendor\MyEnum-native.php

<?php declare(strict_types=1);

namespace Vendor;

use Mabe\Enum\Cl\EnumBc;

enum MyEnum:int
{
    use EnumBc;

    case ZERO = 0;
    case ONE = 1;
    case TWO = 2;
    case THREE = 3;
    case FOUR = 4;
    case FIVE = 5;
    case SIX = 6;
    case SEVEN = 7;
    case EIGHT = 8;
    case NINE = 9;
}
Enum type native emulated
Unit enum
enum ENUMNAME {
use \Mabe\Enum\Cl\EnumBc;
case CASENAME;
// ...
}
final class ENUMNAME extends \Mabe\Enum\Cl\EmulatedUnitEnum {
protected const CASENAME = null;
// ...
}
Integer backed enum
enum ENUMNAME:int {
use \Mabe\Enum\Cl\EnumBc;
case CASENAME = CASEVALUE;
// ...
}
final class ENUMNAME extends \Mabe\Enum\Cl\EmulatedIntEnum {
protected const CASENAME = CASEVALUE;
// ...
}
String backed enum
enum ENUMNAME:string {
use \Mabe\Enum\Cl\EnumBc;
case CASENAME = 'CASEVALUE';
// ...
}
final class ENUMNAME extends \Mabe\Enum\Cl\EmulatedStringEnum {
protected const CASENAME = 'CASEVALUE';
// ...
}

For IDE and static code analyzers I recommend adding the following docblock:

/**
 * @method static self CASENAME()
 */

How-to use

The following will work the same on PHP<8.1 (using emulated enums) and on PHP>=8.1 (using native enums):

<?php declare(strict_types=1);

namespace Vendor;

use function Mabe\Enum\Cl\enum_exists;

$zero = MyEnum::ZERO();
$zero = MyEnum::from(0);
$zero = MyEnum::tryFrom(0);
$cases = MyEnum::cases();

$zero->value; // 0
$zero->name;  // ZERO

$zero instanceof \UnitEnum;   // true
$zero instanceof \BackedEnum; // true

MyEnum::ZERO() === MyEnum::from(0);     // true
MyEnum::from(0) === MyEnum::tryFrom(0); // true

enum_exists(MyEnum::class); // true
enum_exists('stdClass');    // false

Warning: The following will not behave the same on all PHP versions:

<?php declare(strict_types=1);

namespace Vendor;

MyEnum::ZERO; // PHP<8.1:  Error: Cannot access protected const MyEnum::ZERO
              // PHP>=8.1: enum(MyEnum::ZERO)

serialize(MyEnum::ZERO()); // PHP<8.1:  Error: Trying to serialize a non serializable emulated enum case of MyEnum
                           // PHP>=8.1: "E:11:"MyEnum:ZERO"

Additional Notes

PHPStan

By default PHPStan will complain about unused constants as it can't automatically detect the special use via reflection in this case.

To avoid this you need to add the following to your phpstan.neon[.dist]:

services:
    -
        class: Mabe\Enum\Cl\PHPStan\ConstantExtension
        tags:
            - phpstan.constants.alwaysUsedClassConstantsExtension

For more information please read https://phpstan.org/developing-extensions/always-used-class-constants

Included Polyfills

This library includes the following polyfills (if not already present):

  • get_debug_type

About

Compatibility layer for emulating enumerations in PHP < 8.1 and use native enumerations in PHP >= 8.1

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published