4
\$\begingroup\$

I'm relatively new to PHP and one of the things I miss from other languages are enums. After looking around for some samples on how can I have somewhat similar to them, I came up with this implementation. I want to know how good is it, how can it be improved or any other flaws you can find in it. It's writen in PHP 7.

Base class

abstract class BaseEnum
{
    private $value;

    protected function __construct(string $value) {
        $this->value = $value;
    }

    public function getValue(): string {
        return $this->value;
    }

    public abstract static function parse(?string $value);

    public abstract static function InitializeEnums();
}

This is the base class from where all my "enums" inherit. In short this is an immutable class that hold a single string value and a getter for it (internally all enums will be string, opposed to other languages that are often ints). There is an abstract method that takes a raw string and returns the matching enum instance that needs to be implemented in a case-by-case basis, as well as an initialization method (see below for this).

Concrete enum class

class VoucherType extends BaseEnum {
    private static $invoice;
    private static $creditNote;
    private static $advance;

    public static function InitializeEnums() {
        VoucherType::$invoice = new VoucherType("I");
        VoucherType::$creditNote = new VoucherType("C");
        VoucherType::$advance = new VoucherType("A");
    }

    public static function parse(?string $value): ?self {
        if($value === VoucherType::$invoice->getValue()) return VoucherType::$invoice;
        if($value === VoucherType::$creditNote->getValue()) return VoucherType::$creditNote;
        if($value === VoucherType::$advance->getValue()) return VoucherType::$advance;
        return null;
    }

    public static function invoice(): self {
        return VoucherType::$invoice;
    }
    public static function creditNote(): self {
        return VoucherType::$creditNote;
    }
    public static function advance(): self {
        return VoucherType::$advance;
    }
}
VoucherType::InitializeEnums();

This is one of my real enum classes. All that it does is to provide the fixed valid values and appropriate getters for each one. Also implements the parse that looks each value in turn. It stores singletons of each possible value and those are returned as needed. The initialization of the singletons is done via the InitializeEnums method, which is called outside the class (a dirty trick to simulate a static constructor).

This enables to make simple comparisons with "constant" values like $var == VoucherType::invoice(), or to convert to/from string with appropriate invalid values handling (and replaced with nulls). Variables will always be from this class type (and not simple strings) and assignment/comparision works as expected.

How can I improve it and what's good, bad or should change about it?

\$\endgroup\$
1
\$\begingroup\$

I would simulate the enum using class constants.

class VoucherType {
  const INVOICE = 0;
  const CREDIT_NOTE = 1;
  const ADVANCE = 2;
}

$myType = VoucherType::INVOICE;

They are accesible from everywhere you can access the class, virtually everywhere if you use (and you should) an autoloader.

This is a readable and well-known pattern but there are more sophisticated options, starting with SplEnum and ending with php7-enum, but I like the simplicity of the constants.

Also I you are new to PHP I recommend you to read other's code to learn and get used to the language.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.