Enum support

  Status: implemented,  Tue Jul 31 13:39:28 2007
  • Created: 2007-07-03 21:12:43+0200
  • Categories: <core>
  • Author: friebe

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:

  /**
* 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

  /**
* 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"

  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:

  $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:

  class MethodWrapper extends Object {

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

Usage: Printing

The following will print "MANDATORY" to the console:

  Console::writeLine(TransactionType::$MANDATORY);

Usage: Using enums in switch

  $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:

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



Example: Coin

  // 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

- RFC #0009: Typesafe enumerations (PHP5) Enum support in PHP5 with patched Zend Engine

- http://experiments.xp-framework.net/?arena,enum Experiments and demos

- http://xp-framework.info/xml/xp.en_US/news/view?199 EASC and enums

- http://xp-framework.info/xml/xp.en_US/news/view?207 Enum usecases: Profiling

Comments



<EOF>


Table of contents