Implementing Enum Using Late Static Binding in PHP

It has been a while since i programmed in Java. One of the type features of Java that can be implemented in PHP is Enum, which might come in handy in some situations. This can be done using the Late Static Binding feature in PHP.

Static Binding

If we try to access a static method with same signature in both the extended class and extending class then the method resolves only to the class method that it is defined in.

<?php
class Foo {
    public static function whoami() {
        echo __CLASS__;
    }
    public static function staticAccess() {
        self::whoami();
    }
}

class Baz extends Foo {
    public static function whoami() {
        echo __CLASS__;
    }
}

Baz::staticAccess();
?>

Output

Foo

The above example will output Foo as the method whoami is declared inside the Foo class.

Late Static Binding

With the help of late static binding we can access the method inside the class that is used to access it using the static keyword. From the above example, instead of self::whoami in the staticAccess() method, we need to place static::staticAccess(). This way when we access staticAccess() method using Baz class it will output Baz.

<?php
class Foo {
    public static function whoami() {
        echo __CLASS__;
    }
    public static function staticAccess() {
        static::whoami();
    }
}

class Baz extends Foo {
    public static function whoami() {
        echo __CLASS__;
    }
}

Baz::staticAccess();
?>

Output

Foo

Enum using LSB

I have used Late Static Binding to create a set of Interface and Abstract class to implement this enum.

interface IEnum {
  /**
   * Only concrete class should implement this function that should behave as
   * an enum.
   * 
   * This method should return the __CLASS__ constant property of that class
   * 
   * @return string __CLASS__
   */
  public static function who();
}

abstract class Enum {

  /**
   * The selected value for the enum implementation
   * 
   * @var mixed
   */
  public $value;
  
  public function __construct($value) {
    $this->value = $value;
  }
  
  /**
   * The factory method that creates the corresponding enum class.
   * 
   * @param integer $type
   * @return false|\class
   */
  public static function Factory($type) {
    if (empty($type)) {
      return false;
    }
    
    // use of late static binding to get the class.
    $class = static::who();
    
    if (array_key_exists($type, static::$_enums)) {
      return new $class($type);
    }
    
    return false;
  }
  
  public function getValue() {
    return $this->value;
  }
  
  public static function getValues() {
    return array_keys(static::$_enums);
  }
  
  public function getString() {
    return static::$_enums[$this->value];
  }
  
  public function __toString() {
    return static::$_enums[$this->value];
  }

}

Usage

class Fruits extends Enum implements IEnum {

      public static $_enums = array(
            1 => 'Apple'
            2 => 'Orange'
            3 => 'Banana'
      )

      public static function who() {
             return __CLASS__;
      }
}

// user input from dropdown menu of fruits list
$input = 3;

$fruit = Fruits::Factory($input);

$fruit->getValue();
$fruit->getString();

Output

3
Banana

Let me know your thoughts on this in the comments.