rfc:enum

This is an old revision of the document!


PHP RFC: Enumerated Types

Introduction

Often programmers encounter data that is naturally represented as small finite set of exclusive values. Currently in PHP there is no convenient type-safe way to represent these data sets. This RFC proposes to add syntax and semantics to facilitate representing this kind of data.

Proposal

Enums are given a name and a finite list of unique, case-sensitive values. Enum types share the same symbol table as classes, interfaces and traits. Names that are invalid for classes are also invalid for enum types. Enum types are implicitly final; they cannot be extended. Enums are not editable after definition in any way. Using an enum type that isn't loaded will trigger the autoloader just like a unloaded class. Enum values can be serialized.

Syntax

Here is a definition of an enum type RenewalAction with two values Deny and Approve:

enum RenewalAction {
    Deny,
    Approve
}

To access an enum value use the enum type name followed by two colons and then the name of the value (e.g. RenewalAction::Deny). This is the same syntax for accessing class constants.

Use in Type Declarations

Enums are strongly typed and can be used as parameter or return types. They can also be used in case statements.

function other(RenewalAction $action): RenewalAction {
    switch ($action) {
        case RenewalAction::Approve:
            return RenewalAction::Deny;
 
        case RenewalAction::Deny:
            return RenewalAction::Approve;
    }
}
other(RenewalAction::Approve);

Equality and Comparisons

An enum value is only equal to itself. Comparing an enum value to anything except itself evaluates to false. Due to the semantics of the <=> operator, comparing an enum value to anything except itself will evaluate to 1.

enum Foo { A, B }
 
// bool(true)
var_dump(Foo::A === Foo::A); 
 
// bool(false)
var_dump(Foo::A === Foo::B); 
 
// int(0)
var_dump(Foo::A <=> Foo::A);
 
// int(1)
var_dump(Foo::A <=> Foo::B);
var_dump(Foo::B <=> Foo::A);

TODO: figure out if enums can always override comparisons with objects that implement the compare handler.

Reflection

TODO: Figure out appropriate reflection operations. Maybe:

  • Add isEnum(): bool to ReflectionClass? Or add a separate ReflectionEnum?
  • Ensure getConstant() and getConstants() work correctly.

Backwards Compatibility

This RFC adds a new token T_ENUM. This means that if the name enum is used for a function, class, trait or interface there will now be a parse error instead.

There are no other known backwards compatibility breaks.

TODO: figure out if the context sensitive lexer changes affect this.

Voting

The vote will be a simple “yes” or “no” and requires 2/3 of the votes to be “yes” to pass. This RFC targets PHP version 7.1 .

Explanation of Implementation

TODO: update this once Bob has finished his implementation.

Patches and Tests

A proof of concept implementation can be found on this branch: https://github.com/morrisonlevi/php-src/tree/enum. A proper implementation will be provided by Bob Weinand.

Future Scope

A few ideas for things that could potentially happen:

  1. Algebraic data types and pattern matching:
    enum Maybe {
        None,
        Some($t)
    }
     
    match ($maybe) {
        case Maybe::None {
            echo "None";
        }
        case Maybe::Some($t) {
            echo "Some($t)";
        }
    }
  2. User defined methods:
    enum Direction {
        North {
            function opposite(): Direction {
                return Direction::South;
            }
        },
        East {
            function opposite(): Direction {
                return Direction::West;
            }
        },
        South {
            function opposite(): Direction {
                return Direction::North;
            }
        },
        West {
            function opposite(): Direction {
                return Direction::East;
            }
        }
    }
  3. Box primitive types, such as what Hack does:
    enum Flags : int {
        a = 1 << 0,
        b = 1 << 1,
        c = 1 << 2,
        d = 1 << 3
    }

These ideas are not necessarily fully compatible, so we should choose carefully on further expansions to enums.

rfc/enum.1449892692.txt.gz · Last modified: 2017/09/22 13:28 (external edit)