xp-framework / core

The XP Framework is an all-purpose, object oriented PHP framework.
Other
19 stars 6 forks source link

Add enum_exists() as well as UnitEnum and BackedEnum interfaces #261

Closed thekid closed 3 years ago

thekid commented 3 years ago

Forwards compatibility with PHP 8.1 enumerations

See https://wiki.php.net/rfc/enumerations

thekid commented 3 years ago

Test all this with a PHP 8.1 version with [...enum support...]

Obviously, since Enum is now a reserved word, one cannot declare a class with that. This breaks lang.Enum.

# Patch & compile
thekid@Surface:~/bin/php$ curl https://patch-diff.githubusercontent.com/raw/php/php-src/pull/6489.patch | patch -p1
thekid@Surface:~/bin/php$ make clean && ./buildconf && ./config.nice && make
# ...

# Verify enum support is available
thekid@Surface:~/bin/php$ ./sapi/cli/php -r 'enum SortOrder { case ASC; case DESC; } var_dump(SortOrder::ASC);'
enum(SortOrder::ASC)

# Run tests
thekid@Surface:[...]/devel/xp/core$ XP_RT=master xp xp.unittest.Runner src/test/config/unittest/core.ini
Uncaught exception: ParseError (syntax error, unexpected token "enum", expecting identifier)
  at <source> [line 10 of ./src/main/php/lang/Enum.class.php]
# ...

We would need to rename the Enum class to XPEnum (following the XPClass idiom). We should be able to do this BC break free for PHP 7 and PHP 8.0 by aliasing Enum to XPEnum.

iluuu1994 commented 3 years ago

Obviously, since Enum is now a reserved word, one cannot declare a class with that. This breaks lang.Enum.

We've actually changed this recently to ease migration.

https://wiki.php.net/rfc/enumerations

Thanks to a clever trick from Nikita (discussed after the RFC was approved), “enum” is not a reserved word on its own. That means it is still a legal name for a class/interface/trait at this time. It will likely be converted into a full keyword at some point in the future, but this RFC does not specify that timeline. As a side effect, comments are not supported between “enum” and the Enum name, which is of little consequence in practice.

So your class name should not break.

thekid commented 3 years ago

So your class name should not break.

There is a glitch in this implementation, @iluuu1994:

# Works as expected
thekid@Surface:~/bin/php$ ./sapi/cli/php -r 'class Enum { }'

# Breaks
thekid@Surface:~/bin/php$ ./sapi/cli/php -r 'interface Value { } class Enum implements Value { }'

Parse error: syntax error, unexpected token "enum", expecting identifier in Command line code on line 1`

This is the trick you're referencing:

/*
 * The enum keyword must be followed by whitespace and another identifier.
 * This avoids the BC break of using enum in classes, namespaces, functions and constants.
 */
<ST_IN_SCRIPTING>"enum"{WHITESPACE}[a-zA-Z_\x80-\xff] {
        yyless(4);
        RETURN_TOKEN_WITH_IDENT(T_ENUM);
}

The problem is that in class Enum implements Value, the string implements fulfills this rule, yielding the following tokens: T_CLASS T_ENUM T_IMPLEMENTS T_STRING("Value"), however, the class declaration rule expects T_CLASS T_STRING, thus causing this parse error.

iluuu1994 commented 3 years ago

Oh right, thanks for the heads up. Glad you tested that.

iluuu1994 commented 3 years ago

@thekid Pushed a fix, does this resolve the problem?

thekid commented 3 years ago

@thekid Pushed a fix, does this resolve the problem?

Yes, it does:

# After applying the newer patch:
thekid@Surface:~/bin/php$ ./sapi/cli/php -r 'interface Value { } class Enum implements Value { } var_dump(new Enum());'
object(Enum)#1 (0) {
}

Thanks @iluuu1994 ☀

iluuu1994 commented 3 years ago

Great! Thanks for testing :slightly_smiling_face:

thekid commented 3 years ago

Test results

PHP 8.0:

$ XP_RT=8.0 xp test src/test/php/net/xp_framework/unittest/core/EnumTest.class.php
# ...

♥: 41/45 run (4 skipped), 41 succeeded, 0 failed
Memory used: 2335.88 kB (2544.44 kB peak)
Time taken: 0.079 seconds

PHP 8.1 with enums:


$ XP_RT=master xp xp.unittest.Runner src/test/php/net/xp_framework/unittest/core/EnumTest.class.php
# ...

♥: 45/45 run (0 skipped), 45 succeeded, 0 failed
Memory used: 2250.23 kB (2646.16 kB peak)
Time taken: 0.065 seconds
thekid commented 3 years ago

Released in https://github.com/xp-framework/core/releases/tag/v10.8.0