xp-framework / compiler

Compiles future PHP to today's PHP.
19 stars 0 forks source link

Compile PHP enums to PHP 7/8 lookalikes, PHP 8.1 native #106

Closed thekid closed 3 years ago

thekid commented 3 years ago

Enums

Implement feature request #100. XP Compiler and XP Framework (10.8.0+) now support:

⚠️ The xp-enums compiler extension, which defines an alternate enum syntax and compiles it to XP enums, will be deprecated! Its abstract enum feature is unsupported by PHP 8.1 enums, and may be reintroduced later via the tagged unions RFC.

Behind the scenes

What the user writes (and what will be emitted for PHP 8.1 once the enum PR is merged):

// Declaration
enum Suit {
  case Hearts;
  case Diamonds;
  case Clubs;
  case Spades;
}

// Usage
$e= Suit::Spades;

What is emitted for PHP < 8.1:

// Declaration
final class Suite implements UnitEnum {
  public static $Hearts, $Diamonds, $Clubs, $Spades;
  public $name;

  static function __static() {
    self::$Hearts= new self('Hearts');
  }

  /** @param string $name */
  public function __construct($name) { $this->name= $name; }

  /** UnitEnum implementation */
  public static function cases(): array {
    return [self::$Hearts, self::$Diamonds, self::$Clubs, self::$Spades];
  }
}

// Usage
$e= Suit::$Spades;

Backed enums also include a value member as well as from() and tryFrom() methods.

thekid commented 3 years ago

:shipit: Released in https://github.com/xp-framework/compiler/releases/tag/v6.3.0

thekid commented 3 years ago

The xp-enums compiler extension [...] will be deprecated! Its abstract enum feature is unsupported by PHP 8.1 enums [...]

...and with support for arbitrary expressions as initializers (see #104), we can simply refactor code as follows:

@@ -3,8 +3,8 @@
 use xml\{Tree, Node};

 /** CAS service response - in XML and JSON */
-abstract enum ServiceResponse {
-  XML {
+abstract class ServiceResponse {
+  public static $XML= new class() extends self {
     public function success($user) {
       $n= new Node('cas:authenticationSuccess')->withChild(new Node('cas:user', $user['username']));
       if (isset($user['attributes'])) {
@@ -29,8 +29,8 @@ abstract enum ServiceResponse {

       $response->send($tree->getSource(INDENT_DEFAULT), 'text/xml');
     }
-  },
-  JSON {
+  };
+  public static $JSON= new class() extends self {
     public function success($user) {
       $success= ['user' => $user['username']];
       if (isset($user['attributes'])) {

(In this case, the class already had a static factory method and wasn't using Enum::valueOf(), so no further adjustments needed to be made)

thekid commented 3 years ago

PHP 8.1 enums on PHP 8.1 with [enum PR] merged

PHP master build donwloaded from https://github.com/shivammathur/php-builder-windows/actions:

# Verify enum support
$ XP_RT=master xp -w 'enum SortOrder { case ASC; case DESC; } return SortOrder::ASC'
SortOrder {
  name => "ASC"
}

# Run XP core tests
core $ XP_RT=master xp test src/test/config/unittest/*ini
# ...
♥: 4205/4259 run (54 skipped), 4205 succeeded, 0 failed
Memory used: 22559.28 kB (43149.24 kB peak)
Time taken: 4.005 seconds

# Run XP compiler test
compiler $ XP_RT=master xp test src/test/php
# ...
♥: 563/564 run (1 skipped), 563 succeeded, 0 failed
Memory used: 9119.41 kB (9177.58 kB peak)
Time taken: 0.251 seconds