2

I basically want an enum-like class in PHP. My enum should have a few values (they are all static). Let's say I want to have an enum that has an ID (the ID must never, ever change), and a name (the name must not change during runtime, it can change during compile-time -- e.g. from changes made to the code). The state must not have any side-effects (i.e. they are only getters and instance variables cannot be changed). A state must also not be created during runtime except when initializing the class.

For my concert example, I have three possible states: OPEN, CLOSED, and UNKOWN:

class MyState {
    const STATE_OPEN = new MyState(1, "open");
    const STATE_CLOSE = new MyState(2, "closed");
    const STATE_UNKOWN = new MyState(3, "unkown");

    private $name;
    private $state;

    private function __construct(int $state, string $name) {
        $this->state = $state;
        $this->name = $name;
    }

    public function getName() : string {
        return $this->name;
    }

    public function getState() : int {
        return $this->state;
    }

    public function getStateByID(int $state) : MyState { ... }
    public function getStateByName(string $name) : MyState { ... }
}

I want to refer to each state unambiguously in my code (MyState::STATE_OPEN, etc). This should also ensure that a compiler/linter/etc can verify that the state actually exists (there is no guarantee that getStateByID does not throw an exception).

There are also some (de)serializers that can load a state after it has been saved (by using the never changing ID).

Unfortunately, I cannot set const or static instance variables if their object is from the same class. I get the following error:

Constant expression contains invalid operations

How can this be best accomplished in PHP? I know I can easily create an enum with just an int (class MyState { const STATE_OPEN = 1; }) but that has a major disadvantage: the enum is not an object and thus cannot have methods. I cannot use type hinting this way and I might pass an invalid enum. E.g., function takeMyState(int $state) can actually use an enum that has never been defined.

Matt3o12
  • 4,192
  • 6
  • 32
  • 47

1 Answers1

1

Replace your const lines

  const STATE_OPEN = new MyState(1, "open");

by public functions:

  public function STATE_OPEN() { return new MyState(1, "open"); }

resulting in an example program like this:

class MyState {
  public function STATE_OPEN() { return new MyState(1, "open"); }
  public function STATE_CLOSED() { return new MyState(2, "closed"); }
  public function STATE_UNKNOWN() { return new MyState(3, "unknown"); }

  private $name;
  private $state;

  private function __construct(int $state, string $name) {
    $this->state = $state;
    $this->name = $name;
  }

  public function getName() : string {
    return $this->name;
  }

  public function getState() : int {
    return $this->state;
  }
}

$state = MyState::STATE_CLOSED();

echo $state->getName() . "(" . $state->getState() . ")\n";
Mark Roberts
  • 138
  • 7