Skip to content

Commit 9a5bdc5

Browse files
committed
Remove class for enum case
1 parent 1fac0ce commit 9a5bdc5

20 files changed

+84
-223
lines changed

Zend/tests/enum/003.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,5 @@ try {
3131

3232
?>
3333
--EXPECTF--
34-
takesBaz(): Argument #1 ($baz) must be of type Baz, Foo::Bar given, called in %s on line %d
35-
takesFoo(): Argument #1 ($foo) must be of type Foo, Baz::Qux given, called in %s on line %d
34+
takesBaz(): Argument #1 ($baz) must be of type Baz, Foo given, called in %s on line %d
35+
takesFoo(): Argument #1 ($foo) must be of type Foo, Baz given, called in %s on line %d

Zend/tests/enum/005.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ interface Colorful {
77
public function color(): string;
88
}
99

10-
enum Suit /* implements Colorful */ {
10+
enum Suit implements Colorful {
1111
case Hearts;
1212
case Diamonds;
1313
case Clubs;

Zend/tests/enum/006.phpt

Lines changed: 0 additions & 46 deletions
This file was deleted.

Zend/tests/enum/008.phpt

Lines changed: 0 additions & 16 deletions
This file was deleted.

Zend/tests/enum/010.phpt

Lines changed: 0 additions & 14 deletions
This file was deleted.

Zend/tests/enum/011.phpt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
--TEST--
22
Enum is abstract
3+
--SKIPIF--
4+
<?php
5+
die("skip doesn't work yet");
6+
?>
37
--FILE--
48
<?php
59

Zend/tests/enum/012.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ try {
1717

1818
?>
1919
--EXPECT--
20-
Cannot create dynamic property Foo::Bar::$baz
20+
Cannot create dynamic property Foo::$baz

Zend/tests/enum/014.phpt

Lines changed: 0 additions & 14 deletions
This file was deleted.

Zend/tests/enum/017.phpt

Lines changed: 0 additions & 14 deletions
This file was deleted.

Zend/tests/enum/018.phpt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@ Enum disallows static properties
44
<?php
55

66
enum Foo {
7-
case Bar {
8-
public static $baz;
9-
}
7+
public static $bar;
108
}
119

1210
?>
1311
--EXPECTF--
14-
Fatal error: Enum cases may not include member variables in %s on line %d
12+
Fatal error: Enums may not include member variables in %s on line %d

Zend/tests/enum/020.phpt

Lines changed: 9 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,23 @@
11
--TEST--
2-
Enum case attributes
2+
Enum attributes
33
--FILE--
44
<?php
55

66
#[Attribute]
7-
class EnumValue {
7+
class EnumAttribute {
88
public function __construct(
99
public string $value,
1010
) {}
1111
}
1212

13-
enum Suit {
14-
#[EnumValue('H')] case Hearts;
15-
#[EnumValue('D')] case Diamonds;
16-
#[EnumValue('C')] case Clubs;
17-
#[EnumValue('S')] case Spades;
13+
#[EnumAttribute('Foo')]
14+
enum Foo {}
1815

19-
public function value(): string {
20-
return self::getEnumCaseValue($this::class);
21-
}
22-
23-
public static function from(string $value): self {
24-
$constants = (new \ReflectionClass(__CLASS__))->getConstants();
25-
26-
foreach ($constants as $constant) {
27-
if ($value === self::getEnumCaseValue($constant::class)) {
28-
return $constant;
29-
}
30-
}
31-
32-
throw new \InvalidArgumentException('Unknown enum value ' . $value);
33-
}
34-
35-
private static function getEnumCaseValue(string $caseClass): string {
36-
return (new \ReflectionClass($caseClass))
37-
->getAttributes(EnumValue::class)[0]
38-
->newInstance()
39-
->value;
40-
}
41-
}
42-
43-
var_dump(Suit::Hearts->value());
44-
var_dump(Suit::from('D'));
45-
46-
try {
47-
var_dump(Suit::from('X'));
48-
} catch (\InvalidArgumentException $e) {
49-
echo $e->getMessage() . "\n";
50-
}
16+
var_dump((new \ReflectionClass(Foo::class))->getAttributes(EnumAttribute::class)[0]->newInstance());
5117

5218
?>
5319
--EXPECT--
54-
string(1) "H"
55-
enum(Suit::Diamonds)
56-
Unknown enum value X
20+
object(EnumAttribute)#1 (1) {
21+
["value"]=>
22+
string(3) "Foo"
23+
}

Zend/zend_ast.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -754,14 +754,21 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast
754754
}
755755
}
756756
break;
757-
case ZEND_AST_NEW:
757+
case ZEND_AST_CONST_ENUM_INIT:
758758
{
759-
// FIXME: Assert enum constants
760759
zend_ast *class_name_ast = ast->child[0];
760+
zend_ast *case_name_ast = ast->child[1];
761761
zval *class_name_zv = zend_ast_get_zval(class_name_ast);
762762
zend_string *class_name = Z_STR_P(class_name_zv);
763+
zval *case_name_zv = zend_ast_get_zval(case_name_ast);
763764
zend_class_entry *ce = zend_fetch_class_by_name(class_name, NULL, 0);
764765
object_init_ex(result, ce);
766+
zend_object *zobj = Z_OBJ_P(result);
767+
zend_string *case_property_name = zend_string_init("case", strlen("case"), 0);
768+
769+
zobj->handlers->write_property(zobj, case_property_name, case_name_zv, NULL);
770+
771+
zend_string_free(case_property_name);
765772
break;
766773
}
767774
default:

Zend/zend_ast.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ enum _zend_ast_kind {
149149
ZEND_AST_MATCH_ARM,
150150
ZEND_AST_NAMED_ARG,
151151

152+
// Pseudo node for initializing enums
153+
ZEND_AST_CONST_ENUM_INIT,
154+
152155
/* 3 child nodes */
153156
ZEND_AST_METHOD_CALL = 3 << ZEND_AST_NUM_CHILDREN_SHIFT,
154157
ZEND_AST_NULLSAFE_METHOD_CALL,

Zend/zend_builtin_functions.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1063,7 +1063,7 @@ ZEND_FUNCTION(trait_exists)
10631063

10641064
ZEND_FUNCTION(is_enum)
10651065
{
1066-
class_exists_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_ENUM|ZEND_ACC_ENUM_CASE, 0);
1066+
class_exists_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_ENUM, 0);
10671067
}
10681068

10691069
/* {{{ Checks if the function exists */

Zend/zend_compile.c

Lines changed: 23 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -6765,9 +6765,6 @@ zend_string *zend_begin_method_decl(zend_op_array *op_array, zend_string *name,
67656765
if ((ce->ce_flags & ZEND_ACC_ENUM) && zend_is_constructor(name)) {
67666766
zend_error_noreturn(E_COMPILE_ERROR, "Enums cannot contain constructors");
67676767
}
6768-
if ((ce->ce_flags & ZEND_ACC_ENUM_CASE) && zend_is_constructor(name)) {
6769-
zend_error_noreturn(E_COMPILE_ERROR, "Enum cases cannot contain constructors");
6770-
}
67716768

67726769
if (in_interface) {
67736770
if (!(fn_flags & ZEND_ACC_PUBLIC) || (fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_ABSTRACT))) {
@@ -7014,10 +7011,6 @@ void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t flags, z
70147011
zend_error_noreturn(E_COMPILE_ERROR, "Enums may not include member variables");
70157012
}
70167013

7017-
if (ce->ce_flags & ZEND_ACC_ENUM_CASE) {
7018-
zend_error_noreturn(E_COMPILE_ERROR, "Enum cases may not include member variables");
7019-
}
7020-
70217014
if (flags & ZEND_ACC_ABSTRACT) {
70227015
zend_error_noreturn(E_COMPILE_ERROR, "Properties cannot be declared abstract");
70237016
}
@@ -7134,11 +7127,6 @@ void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_ast *attr
71347127
return;
71357128
}
71367129

7137-
if (ce->ce_flags & ZEND_ACC_ENUM_CASE) {
7138-
zend_error_noreturn(E_COMPILE_ERROR, "Enum cases cannot have constants");
7139-
return;
7140-
}
7141-
71427130
for (i = 0; i < children; ++i) {
71437131
zend_class_constant *c;
71447132
zend_ast *const_ast = list->child[i];
@@ -7434,6 +7422,15 @@ zend_class_entry *zend_compile_class_decl(znode *result, zend_ast *ast, zend_boo
74347422
zend_verify_abstract_class(ce);
74357423
}
74367424

7425+
if (ce->ce_flags & ZEND_ACC_ENUM) {
7426+
zval default_value;
7427+
ZVAL_NULL(&default_value);
7428+
zend_string *case_property_name = zend_string_init("case", strlen("case"), 0);
7429+
zend_type case_type = ZEND_TYPE_INIT_NONE(0);
7430+
zend_declare_typed_property(ce, case_property_name, &default_value, ZEND_ACC_PUBLIC, NULL, case_type);
7431+
zend_string_release(case_property_name);
7432+
}
7433+
74377434
CG(active_class_entry) = original_ce;
74387435

74397436
if (toplevel) {
@@ -7518,63 +7515,36 @@ zend_class_entry *zend_compile_class_decl(znode *result, zend_ast *ast, zend_boo
75187515
}
75197516
/* }}} */
75207517

7521-
static void zend_declare_enum_case_constant(zend_ast *ast, zend_class_entry *enum_class, zend_class_entry *enum_case_class)
7518+
static void zend_declare_enum_case_constant(zend_ast *ast, zend_class_entry *enum_class)
75227519
{
75237520
zend_ast_decl *enum_case_decl = (zend_ast_decl *) ast;
75247521
zend_string *enum_case_name = enum_case_decl->name;
7525-
zend_string *enum_case_class_name = enum_case_class->name;
7522+
zend_string *enum_class_name = enum_class->name;
7523+
75267524
zval class_name_zval;
7527-
ZVAL_STR_COPY(&class_name_zval, enum_case_class_name);
7525+
ZVAL_STR_COPY(&class_name_zval, enum_class_name);
75287526
zend_ast *class_name_ast = zend_ast_create_zval_ex(&class_name_zval, ZEND_NAME_NOT_FQ);
7529-
zend_ast *new_ast = zend_ast_create(ZEND_AST_NEW, class_name_ast, NULL);
7527+
7528+
zval case_name_zval;
7529+
ZVAL_STR_COPY(&case_name_zval, enum_case_name);
7530+
zend_ast *case_name_ast = zend_ast_create_zval_ex(&case_name_zval, ZEND_NAME_NOT_FQ);
7531+
7532+
zend_ast *const_enum_init_ast = zend_ast_create(ZEND_AST_CONST_ENUM_INIT, class_name_ast, case_name_ast);
75307533

75317534
zval value_zv;
7532-
zend_const_expr_to_zval(&value_zv, &new_ast);
7535+
zend_const_expr_to_zval(&value_zv, &const_enum_init_ast);
75337536
zend_declare_class_constant_ex(enum_class, enum_case_name, &value_zv, ZEND_ACC_PUBLIC, NULL);
75347537

7535-
zend_ast_destroy(new_ast);
7538+
zend_ast_destroy(const_enum_init_ast);
75367539
}
75377540

75387541
static void zend_compile_enum_case_class(zend_ast *ast)
75397542
{
75407543
zend_ast_decl *enum_case_decl = (zend_ast_decl *) ast;
75417544

75427545
zend_class_entry *enum_class = CG(active_class_entry);
7543-
CG(active_class_entry) = NULL;
7544-
7545-
zend_string *enum_class_name = enum_class->name;
7546-
zend_string *enum_case_name = enum_case_decl->name;
7547-
zend_string *enum_case_class_name = zend_string_concat3(
7548-
ZSTR_VAL(enum_class_name), ZSTR_LEN(enum_class_name),
7549-
"::", sizeof("::") - 1,
7550-
ZSTR_VAL(enum_case_name), ZSTR_LEN(enum_case_name)
7551-
);
7552-
7553-
zend_ast *extends_from = zend_ast_create_zval_from_str(enum_class_name);
7554-
7555-
zend_ast *implements_list = enum_case_decl->child[1];
7556-
if (implements_list == NULL) {
7557-
implements_list = zend_ast_create_list(0, ZEND_AST_NAME_LIST);
7558-
}
7559-
7560-
zval enum_interface_name_zv;
7561-
ZVAL_INTERNED_STR(&enum_interface_name_zv, ZSTR_KNOWN(ZEND_STR_ENUM));
7562-
zend_ast *enum_interface_name_ast = zend_ast_create_zval_ex(&enum_interface_name_zv, ZEND_NAME_FQ);
7563-
zend_ast_list_add(implements_list, enum_interface_name_ast);
7564-
7565-
zend_ast *statement_list = enum_case_decl->child[2];
7566-
zend_ast *attribute_list = enum_case_decl->child[3];
7567-
7568-
zend_ast_decl *enum_case_class_decl = (zend_ast_decl *) zend_ast_create_decl(ZEND_AST_CLASS, enum_case_decl->flags, ast->lineno, NULL, enum_case_class_name, extends_from, implements_list, statement_list, attribute_list, NULL);
7569-
zend_class_entry *enum_case_class = zend_compile_class_decl(NULL, (zend_ast *) enum_case_class_decl, 0);
7570-
7571-
CG(active_class_entry) = enum_class;
7572-
7573-
enum_case_class_decl->child[2] = NULL;
7574-
enum_case_class_decl->child[3] = NULL;
7575-
zend_ast_destroy((zend_ast *) enum_case_class_decl);
75767546

7577-
zend_declare_enum_case_constant(ast, enum_class, enum_case_class);
7547+
zend_declare_enum_case_constant(ast, enum_class);
75787548

75797549
zend_ast *enum_primitive_expr_ast = enum_case_decl->child[4];
75807550
if (enum_primitive_expr_ast != NULL) {
@@ -9284,7 +9254,7 @@ zend_bool zend_is_allowed_in_const_expr(zend_ast_kind kind) /* {{{ */
92849254
|| kind == ZEND_AST_CONST || kind == ZEND_AST_CLASS_CONST
92859255
|| kind == ZEND_AST_CLASS_NAME
92869256
|| kind == ZEND_AST_MAGIC_CONST || kind == ZEND_AST_COALESCE
9287-
|| kind == ZEND_AST_NEW; // FIXME: Only allow new for enum constants
9257+
|| kind == ZEND_AST_CONST_ENUM_INIT;
92889258
}
92899259
/* }}} */
92909260

0 commit comments

Comments
 (0)