rfc:enum

Request for Comments: Enum

The old (Pierrick) version of the enum RFC can be found at https://wiki.php.net/rfc/enum?rev=1302087566

This RFC is about adding the enum language structure.

Introduction

When writing a program, it is often required to create lists of constants representing integers to make the code more readable. This RFC introduce a new language construct to define such a list by assigning unique arbitrary values or not.

Why do we need enum

Frequently developers need to produce code like this:

const	LOG_LEVEL_DEBUG = 1,
	LOG_LEVEL_INFO = 2,
	LOG_LEVEL_WARNING = 3,
	LOG_LEVEL_ERROR = 4;
 
// Or
 
class Tokens {
	const	T_IF = 258,
		T_ELSE = 259,
		T_WHILE = 260,
		T_DO = 261;
}

The proposal is that this could be written in a much more concise manner:

enum { 
	LOG_LEVEL_DEBUG,
	LOG_LEVEL_INFO,
	LOG_LEVEL_WARNING,
	LOG_LEVEL_ERROR 
};
 
// Or
 
class Tokens {
	enum { 
		T_IF = 258,
		T_ELSE,
		T_WHILE,
		T_DO 
	};
}

Proposal and Patch

namespace Cards;
 
enum Suit {
	SPADES => '1',
	HEARTS => 2,
	DIAMONDS, // Will have value 3
	CLUBS,    // Will have value 4
}
 
var_dump( Suit::SPADES );         // enum(Cards\Suit)(1)
var_dump( Suit::SPADES == 1 );    // bool(true)
var_dump( Suit::SPADES === 1 );   // bool(true) - because the value is cast to an integer upon declaration
var_dump( Suit::SPADES == '1' );  // bool(true)
var_dump( Suit::SPADES === '1' ); // bool(false)

Declaration

The keyword enum is reserved. An enum may be defined wherever a class or interface could be defined, and the same namespacing, naming and referencing restrictions apply.

Within the enum is a comma-separated list of variable names. Each variable name may optionally be followed by the array operator and a value. The same logic is used for assigning values to the enum members as for assigning keys to arrays: for explicit assignments the same casting of numbers to integers is used, and for implicit assignments the smallest non-negative integer greater than all the previous values is used. Unlike array declarations, however, a duplicate value causes a fatal error.

Use

An enum member may be referenced as EnumName::VALUE just like a class constant.

A scalar may be (explicitly or implicitly) cast to an enum member:

// Using declaration of Suit above
var_dump( (Suit)1 );       // enum(Cards\Suit)(1)
var_dump( (Suit)true );    // enum(Cards\Suit)(1)
var_dump( (Suit)('one') ); // null

An enum may be cast to another type by applying the normal cast operations to its value.

An enum member satisfies the is_*() tests that would be satisfied by its value, but also a new is_enum() function is introduced. This apparent inconsistency is equivalent to the situation with callables, where a string satisfied both is_string() and is_callable(), so is not without precedent.

// Using declaration of Suit above
var_dump( is_string( Suit::SPADES ) ); // bool(false) - since the value is an integer
var_dump( is_int( Suit::SPADES ) );    // bool(true)
 
var_dump( is_enum( Suit::SPADES ) );   // bool(true)
$spades = Suit::SPADES;
var_dump( is_enum( $spades ) );        // bool(true)
var_dump( is_int( $spades ) );         // bool(true)
 
// Compare:
function callableFunction(){}
$callable = 'callableFunction';
var_dump( is_callable( $callable ) );  // bool(true)
var_dump( is_string( $callable ) );    // bool(true)

Possible alterations

  • Requiring the existing const keyword before the enum; this largely eliminates B/C issues.
rfc/enum.txt · Last modified: 2014/04/09 00:56 by levim