rfc:enum_v2
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
rfc:enum_v2 [2020/05/13 22:35] – created maxsem | rfc:enum_v2 [2021/02/18 13:14] (current) – Move status to obsolete ilutov | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== PHP RFC: Enumeration type, version 2 ====== | + | ====== PHP RFC: Enumeration type (alternative proposal) |
* Version: 0.9 | * Version: 0.9 | ||
* Date: 2020-05-14 | * Date: 2020-05-14 | ||
* Author: Max Semenik, maxsem.wiki@gmail.com | * Author: Max Semenik, maxsem.wiki@gmail.com | ||
- | * Status: | + | * Status: |
* First Published at: http:// | * First Published at: http:// | ||
+ | |||
+ | //Note: this is a counterproposal to [[rfc: | ||
===== Introduction ===== | ===== Introduction ===== | ||
- | The elevator pitch for the RFC. The first paragraph of this section | + | Traditionally, |
+ | |||
+ | Consider the following perfectly valid code: | ||
+ | <code php> | ||
+ | preg_split($foo, | ||
+ | </ | ||
+ | |||
+ | What will this call produce? I have no idea, either:) | ||
+ | |||
+ | It would be so much better | ||
+ | <code php> | ||
+ | preg_split($foo, | ||
+ | </ | ||
===== Proposal ===== | ===== Proposal ===== | ||
+ | |||
+ | ==== Basics ==== | ||
A simple enum: | A simple enum: | ||
<code php> | <code php> | ||
- | enum foo { | + | enum Letters |
- | a, // Enum values | + | a, // Enum constants |
b, // 1, always previous value +1 if not specified explicitly | b, // 1, always previous value +1 if not specified explicitly | ||
c = 10, // Values can be set explicitly | c = 10, // Values can be set explicitly | ||
d, // 11 | d, // 11 | ||
- | e = 1, // Elements can duplicate | + | e = 1, // Constants with duplicate |
- | f = 2 * 2, // Can use the same expressions as constants | + | f = 2 * 2, // Can use the same expressions as class constants |
- | g = f, // Can use other elements | + | g = f, // Can use other constants too |
h = g + 10, // And in expressions too | h = g + 10, // And in expressions too | ||
- | H, // Valid, | + | H, // Valid, |
- | i, // Optional comma after the last element | + | i, // Optional comma after the last constant |
} | } | ||
</ | </ | ||
+ | |||
+ | A binary enum is used to represent a set of values: | ||
+ | <code php> | ||
+ | binary enum FileMode { | ||
+ | Read = 1, | ||
+ | Write = 2, | ||
+ | Execute = 1 << 2, | ||
+ | ReadWrite = Read | Write, | ||
+ | } | ||
+ | |||
+ | $foo = FileMode:: | ||
+ | </ | ||
+ | |||
+ | Both enum types can extend other enums: | ||
+ | <code php> | ||
+ | enum A { foo = 1 } | ||
+ | |||
+ | enum B extends A { bar = 2 } | ||
+ | |||
+ | $x = B::foo; | ||
+ | </ | ||
+ | |||
+ | Overriding constants from base enums is not allowed: | ||
+ | <code php> | ||
+ | enum C extends A { | ||
+ | foo = 3 // CompileError | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Constants must be '' | ||
+ | <code php> | ||
+ | enum foo { | ||
+ | bar = 2 ** 100, // CompileError | ||
+ | baz = 1.5 // CompileError | ||
+ | } | ||
+ | |||
+ | $x = 'this is a string'; | ||
+ | $y = (foo)$x; // TypeError | ||
+ | </ | ||
+ | |||
+ | ==== Type coercion and casts ==== | ||
+ | Enums are implicitly coercible to bool and string: | ||
+ | <code php> | ||
+ | function f(FileMode $mode) { | ||
+ | if ($mode) { | ||
+ | echo "mode: $mode"; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | f(FileMode:: | ||
+ | </ | ||
+ | |||
+ | Enum types can be explicitly cast to each other and '' | ||
+ | <code php> | ||
+ | $foo = (FileMode)123; | ||
+ | $bar = SomeEnum:: | ||
+ | $foo = (FileMode)$bar; | ||
+ | </ | ||
+ | |||
+ | Conversion from other types is not checked, thus enums can hold values not covered by their constants. '' | ||
+ | |||
+ | ==== Enum operations ==== | ||
+ | Enums are immutable and don't support arithmetic operations: | ||
+ | <code php> | ||
+ | $foo = FileMode:: | ||
+ | $foo = FileMode:: | ||
+ | $foo += 1; // TypeError | ||
+ | $bar = $foo + 1; // TypeError | ||
+ | </ | ||
+ | |||
+ | However, binary enums support bitwise operations: | ||
+ | <code php> | ||
+ | $foo = FileMode:: | ||
+ | $foo |= FileMode:: | ||
+ | $foo &= ~FileMode:: | ||
+ | </ | ||
+ | |||
+ | ==== Enum usage ==== | ||
+ | Concrete enum types can be used as typehints: | ||
+ | <code php> | ||
+ | function open(string $filename, FileMode $mode) | ||
+ | </ | ||
+ | However, not the enum keyword itself: | ||
+ | <code php> | ||
+ | function open(string $filename, enum $mode) // CompileError | ||
+ | </ | ||
+ | |||
+ | When the type is clear from typehints, enum name can be omitted: | ||
+ | <code php> | ||
+ | open(' | ||
+ | </ | ||
+ | is equivalent to: | ||
+ | <code php> | ||
+ | open(' | ||
+ | </ | ||
+ | |||
+ | Same for '' | ||
+ | <code php> | ||
+ | function f(Letters $x) { | ||
+ | switch ($x) { | ||
+ | case a: | ||
+ | // ... | ||
+ | case b: | ||
+ | // ... | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ==== Internal representation ==== | ||
+ | Internally, enums are classes and enum constants are public class constants. This makes them the fourth OOP-ey type in PHP, along with '' | ||
+ | <code php> | ||
+ | final // In the sense that userspace can't explicitly extend it | ||
+ | class Enum { | ||
+ | private int $value; | ||
+ | private function __construct(); | ||
+ | public function isBinary(): bool; | ||
+ | public function __toString(): | ||
+ | return (string)(int)$this-> | ||
+ | } | ||
+ | | ||
+ | // Whether the current value is represented by one of this enum's constants | ||
+ | // or their combination for binary enums | ||
+ | public function isKnownValue(): | ||
+ | | ||
+ | // Returns a human readable representation of this enum's value | ||
+ | // e.g. (FileMode:: | ||
+ | // For unrecognized values, returns a decimal (simple enums) or hexadecimal (binary enums) string. | ||
+ | public function toHumanReadableString(): | ||
+ | | ||
+ | public static function parse(string $enum) : ? | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== Conventions used in this document ===== | ||
+ | Currently, PascalCase is used in enums due to author' | ||
+ | |||
+ | Same applies to the '' | ||
===== Backwards Incompatible Changes ===== | ===== Backwards Incompatible Changes ===== | ||
- | `enum` and `binary` will become reserved keywords. | + | '' |
===== Proposed PHP Version(s) ===== | ===== Proposed PHP Version(s) ===== | ||
- | Next PHP 8.x (8.1?) | + | PHP 8.1? |
===== Open Issues ===== | ===== Open Issues ===== | ||
Make sure there are no open issues when the vote starts! | Make sure there are no open issues when the vote starts! | ||
+ | |||
+ | * Naming conventions | ||
+ | * Base class name(s) | ||
+ | * Type coercion details? | ||
===== Unaffected PHP Functionality ===== | ===== Unaffected PHP Functionality ===== | ||
Line 41: | Line 198: | ||
===== Future Scope ===== | ===== Future Scope ===== | ||
- | This section details areas where the feature might be improved in future, but that are not currently proposed in this RFC. | + | After this RFC is implemented, |
===== Proposed Voting Choices ===== | ===== Proposed Voting Choices ===== | ||
- | Include these so readers know where you are heading and can discuss the proposed voting options. | + | * Accept this RFC (yes / no)? |
+ | * What should be enum base class fully qualified name ('' | ||
+ | * What enum constant naming convention should be used (PascalCase / camelCase / UPPER_UNDERSCORED)? | ||
===== Patches and Tests ===== | ===== Patches and Tests ===== | ||
Line 64: | Line 223: | ||
===== References ===== | ===== References ===== | ||
Links to external references, discussions or RFCs | Links to external references, discussions or RFCs | ||
- | * https:// | + | * https:// |
===== Rejected Features ===== | ===== Rejected Features ===== | ||
Keep this updated with features that were discussed on the mail lists. | Keep this updated with features that were discussed on the mail lists. |
rfc/enum_v2.txt · Last modified: 2021/02/18 13:14 by ilutov