8000 Enum support · Issue #132 · xp-framework/rfc · GitHub
[go: up one dir, main page]

Skip to content
Enum support #132
@thekid

Description

@thekid

Scope of Change

There will be a defined way to write enums.

Rationale

Interaction with programming languages with enums, via EASC, for example.

Functionality

Core

A new class, lang.Enum will be added:

<?php
  /**
   * Enumeration
   *
   * @purpose  Abstract base class   
   */
  abstract class Enum extends Object {
    public
      $name     = '';

    protected
      $ordinal  = 0;

    /**
     * Constructor
     *
     * @param   int ordinal default 0
     * @param   string name default ''
     */
    protected function __construct($ordinal= 0, $name= '') {
      $this->ordinal= $ordinal;
      $this->name= $name;
    }

    /**
     * Returns the enumeration member uniquely identified by 
     *
     * @param   lang.XPClass
     * @param   string name enumeration member
     * @return  lang.Enum
     * @throws  lang.IllegalArgumentException
     */
    public static function valueOf(XPClass $class, $name) {
      // ...
    }

    /**
     * Create a string representation of this enum
     *
     * @return  string
     */
    public function toString() {
      return $this->name;
    }

    /**
     * Returns all members for a given enum.
     *
     * @param   string class
     * @return  lang.Enum[]
     */
    protected static function membersOf($class) {
      $c= new ReflectionClass($class);
      return array_values($c->getStaticProperties());
    }
  }
?>

Reflection

The XPClass class will support an isEnum() method

<?php
  /**
   * Determines if this XPClass object represents an enum type.
   *
   * @return  bool
   */
  public function isEnum() {
    // ...
  }
?>

Defining an enum

To create an enum type, the following is necessary:

  • Create public static members with the enum names
    Unfortunately, it is not possible to use class constants because these
    can only be initialized to scalars or constant arrays in PHP.
  • Define a static initializer and initialize them
    PHP does not allow initializing member variables to objects.
  • Implement the values() method with the boilerplate shown below.
    It cannot be enforced that a static values() method should exist, as
    adding public static abstract function values(); to the base class
    will raise an E_STRICT "Static function Enum::values() should not
    be abstract"
<?php
  class TransactionType extends Enum {
    public static
      $NOT_SUPPORTED,
      $REQUIRED,
      $SUPPORTS,
      $REQUIRES_NEW,
      $MANDATORY,
      $NEVER,
      $UNKNOWN;

    static function __static() {
      self::$NOT_SUPPORTED= new self(0, 'NOT_SUPPORTED');
      self::$REQUIRED= new self(1, 'REQUIRED');
      self::$SUPPORTS= new self(2, 'SUPPORTS');
      self::$REQUIRES_NEW= new self(3, 'REQUIRES_NEW');
      self::$MANDATORY= new self(4, 'MANDATORY');
      self::$NEVER= new self(5, 'NEVER');
      self::$UNKNOWN= new self(6, 'UNKNOWN');
    }

    public static function values() {
      return parent::membersOf(__CLASS__);
    }
  }
?>

Usage: Enum values

Enum values can be accessed by the following syntax:

<?php
  $transactionType= TransactionType::$MANDATORY;
?>

Note:

  Because class members cannot be final in PHP enum members can actually 
  be modified at run-time. It is not possible to use class constants for
  the afforementioned reasons.

Usage: Type-safety

Because enums are essentially classes, they can be used as type hints:

<?php
  class MethodWrapper extends Object {

    public function setTransactionType(TransactionType $t) {
      $this->transactionType= $t;
    }
  }
?>

Usage: Printing

The following will print "MANDATORY" to the console:

<?php
  Console::writeLine(TransactionType::$MANDATORY);
?>

Usage: Using enums in switch

<?php
  $transactionType= TransactionType::$MANDATORY;

  // ...later on:
  switch ($transactionType) {
    case TransactionType::$MANDATORY: {
      // ...
      break;
    }

    case TransactionType::$NEVER: {
      // ...
      break;
    }
  }
?>

Note:

  Nothing special, really. PHP supports this as-is.

Usage: Enum values

The following will print all transaction type values to the console:

<?php
  foreach (TransactionType::values() as $type) {
    Console::writeLine('- ', $type);
  }
?>

Example: Coin

<?php
  // Definition
  class Coin extends Enum {
    public static
      $penny,
      $nickel,
      $dime,
      $quarter;

    static function __static() {
      self::$penny= new self(1, 'penny');
      self::$nickel= new self(2, 'nickel');
      self::$dime= new self(10, 'dime');
      self::$quarter= new self(25, 'quarter');
    }

    public static function values() {
      return parent::membersOf(__CLASS__);
    }

    public function value() {
      return $this->ordinal;
    }

    public function color() {
      switch ($this) {
        case self::$penny: return 'copper';
        case self::$nickel: return 'nickel';
        case self::$dime: case self::$quarter: return 'silver';
      }
    }
  }

  // Usage
  foreach (Coin::values() as $coin) {
    echo $coin->name, ': ', $coin->value(), '¢ (', $coin->color(), ")\n";
  }
?>

The above example prints out the following:

  penny: 1¢ (copper)
  nickel: 5¢ (nickel)
  dime: 10¢ (silver)
  quarter: 25¢ (silver)

Security considerations

n/a

Speed impact

n/a

Dependencies

This will increase the minor version

Related documents

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0