From a73b38b2d4086b322cc17b8bd000d009cb94d77a Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Thu, 13 Nov 2025 19:58:22 -0800 Subject: [PATCH 1/9] [RFC] Allow `#[\Override]` on class constants --- .../with_Override_error_constant.phpt | 15 +++++++ .../with_Override_okay.phpt | 4 +- .../override/constants/anon_failure.phpt | 15 +++++++ .../override/constants/anon_interface.phpt | 19 +++++++++ .../override/constants/anon_parent.phpt | 19 +++++++++ .../attributes/override/constants/basic.phpt | 39 +++++++++++++++++++ .../override/constants/failure.phpt | 15 +++++++ .../override/constants/interface_failure.phpt | 15 +++++++ .../override/constants/trait_failure.phpt | 19 +++++++++ .../override/constants/trait_interface.phpt | 23 +++++++++++ .../override/constants/trait_parent.phpt | 23 +++++++++++ .../override/constants/trait_redeclared.phpt | 21 ++++++++++ .../constants/trait_redeclared_interface.phpt | 25 ++++++++++++ .../constants/trait_redeclared_parent.phpt | 25 ++++++++++++ .../override/constants/trait_unused.phpt | 15 +++++++ .../override/constants/visibility_01.phpt | 19 +++++++++ .../override/constants/visibility_02.phpt | 19 +++++++++ .../override/constants/visibility_03.phpt | 19 +++++++++ .../override/constants/visibility_04.phpt | 19 +++++++++ Zend/zend_attributes.stub.php | 2 +- Zend/zend_attributes_arginfo.h | 4 +- Zend/zend_compile.c | 8 ++++ Zend/zend_inheritance.c | 13 +++++++ 23 files changed, 391 insertions(+), 4 deletions(-) create mode 100644 Zend/tests/attributes/delayed_target_validation/with_Override_error_constant.phpt create mode 100644 Zend/tests/attributes/override/constants/anon_failure.phpt create mode 100644 Zend/tests/attributes/override/constants/anon_interface.phpt create mode 100644 Zend/tests/attributes/override/constants/anon_parent.phpt create mode 100644 Zend/tests/attributes/override/constants/basic.phpt create mode 100644 Zend/tests/attributes/override/constants/failure.phpt create mode 100644 Zend/tests/attributes/override/constants/interface_failure.phpt create mode 100644 Zend/tests/attributes/override/constants/trait_failure.phpt create mode 100644 Zend/tests/attributes/override/constants/trait_interface.phpt create mode 100644 Zend/tests/attributes/override/constants/trait_parent.phpt create mode 100644 Zend/tests/attributes/override/constants/trait_redeclared.phpt create mode 100644 Zend/tests/attributes/override/constants/trait_redeclared_interface.phpt create mode 100644 Zend/tests/attributes/override/constants/trait_redeclared_parent.phpt create mode 100644 Zend/tests/attributes/override/constants/trait_unused.phpt create mode 100644 Zend/tests/attributes/override/constants/visibility_01.phpt create mode 100644 Zend/tests/attributes/override/constants/visibility_02.phpt create mode 100644 Zend/tests/attributes/override/constants/visibility_03.phpt create mode 100644 Zend/tests/attributes/override/constants/visibility_04.phpt diff --git a/Zend/tests/attributes/delayed_target_validation/with_Override_error_constant.phpt b/Zend/tests/attributes/delayed_target_validation/with_Override_error_constant.phpt new file mode 100644 index 000000000000..9ebb8e4c0202 --- /dev/null +++ b/Zend/tests/attributes/delayed_target_validation/with_Override_error_constant.phpt @@ -0,0 +1,15 @@ +--TEST-- +#[\DelayedTargetValidation] with #[\Override]: non-overrides still error (class constant) +--FILE-- + +--EXPECTF-- +Fatal error: DemoClass::CLASS_CONSTANT has #[\Override] attribute, but no matching parent constant exists in %s on line %d diff --git a/Zend/tests/attributes/delayed_target_validation/with_Override_okay.phpt b/Zend/tests/attributes/delayed_target_validation/with_Override_okay.phpt index dd077f4b9cbd..494d85eaea9c 100644 --- a/Zend/tests/attributes/delayed_target_validation/with_Override_okay.phpt +++ b/Zend/tests/attributes/delayed_target_validation/with_Override_okay.phpt @@ -12,6 +12,8 @@ class Base { set => $value; } + public const CLASS_CONST = ''; + public function printVal() { echo __METHOD__ . "\n"; } @@ -34,7 +36,7 @@ class DemoClass extends Base { } #[DelayedTargetValidation] - #[Override] // Does nothing here + #[Override] // Does something here public const CLASS_CONST = 'FOO'; public function __construct( diff --git a/Zend/tests/attributes/override/constants/anon_failure.phpt b/Zend/tests/attributes/override/constants/anon_failure.phpt new file mode 100644 index 000000000000..c43cedda81d7 --- /dev/null +++ b/Zend/tests/attributes/override/constants/anon_failure.phpt @@ -0,0 +1,15 @@ +--TEST-- +#[\Override]: Constants - anonymous class, no interface or parent class +--FILE-- + +--EXPECTF-- +Fatal error: class@anonymous::C has #[\Override] attribute, but no matching parent constant exists in %s on line %d diff --git a/Zend/tests/attributes/override/constants/anon_interface.phpt b/Zend/tests/attributes/override/constants/anon_interface.phpt new file mode 100644 index 000000000000..b19abfbf4d3a --- /dev/null +++ b/Zend/tests/attributes/override/constants/anon_interface.phpt @@ -0,0 +1,19 @@ +--TEST-- +#[\Override]: Constants - anonymous class overrides interface +--FILE-- + +--EXPECT-- +Done diff --git a/Zend/tests/attributes/override/constants/anon_parent.phpt b/Zend/tests/attributes/override/constants/anon_parent.phpt new file mode 100644 index 000000000000..b430705c3c9d --- /dev/null +++ b/Zend/tests/attributes/override/constants/anon_parent.phpt @@ -0,0 +1,19 @@ +--TEST-- +#[\Override]: Constants - anonymous class overrides parent class +--FILE-- + +--EXPECT-- +Done diff --git a/Zend/tests/attributes/override/constants/basic.phpt b/Zend/tests/attributes/override/constants/basic.phpt new file mode 100644 index 000000000000..4453ef0a787d --- /dev/null +++ b/Zend/tests/attributes/override/constants/basic.phpt @@ -0,0 +1,39 @@ +--TEST-- +#[\Override]: Constants - basic +--FILE-- + +--EXPECT-- +Done diff --git a/Zend/tests/attributes/override/constants/failure.phpt b/Zend/tests/attributes/override/constants/failure.phpt new file mode 100644 index 000000000000..be621915d927 --- /dev/null +++ b/Zend/tests/attributes/override/constants/failure.phpt @@ -0,0 +1,15 @@ +--TEST-- +#[\Override]: Constants - no interface or parent class +--FILE-- + +--EXPECTF-- +Fatal error: Demo::C has #[\Override] attribute, but no matching parent constant exists in %s on line %d diff --git a/Zend/tests/attributes/override/constants/interface_failure.phpt b/Zend/tests/attributes/override/constants/interface_failure.phpt new file mode 100644 index 000000000000..0aa4d33d1301 --- /dev/null +++ b/Zend/tests/attributes/override/constants/interface_failure.phpt @@ -0,0 +1,15 @@ +--TEST-- +#[\Override]: Constants - no parent interface +--FILE-- + +--EXPECTF-- +Fatal error: IFace::I has #[\Override] attribute, but no matching parent constant exists in %s on line %d diff --git a/Zend/tests/attributes/override/constants/trait_failure.phpt b/Zend/tests/attributes/override/constants/trait_failure.phpt new file mode 100644 index 000000000000..8d4af0e57977 --- /dev/null +++ b/Zend/tests/attributes/override/constants/trait_failure.phpt @@ -0,0 +1,19 @@ +--TEST-- +#[\Override]: Constants - on a trait, no interface or parent class +--FILE-- + +--EXPECTF-- +Fatal error: UsesTrait::T has #[\Override] attribute, but no matching parent constant exists in %s on line %d diff --git a/Zend/tests/attributes/override/constants/trait_interface.phpt b/Zend/tests/attributes/override/constants/trait_interface.phpt new file mode 100644 index 000000000000..3a2ba799ae4e --- /dev/null +++ b/Zend/tests/attributes/override/constants/trait_interface.phpt @@ -0,0 +1,23 @@ +--TEST-- +#[\Override]: Constants - on a trait, overrides interface +--FILE-- + +--EXPECT-- +Done diff --git a/Zend/tests/attributes/override/constants/trait_parent.phpt b/Zend/tests/attributes/override/constants/trait_parent.phpt new file mode 100644 index 000000000000..2753aaf546a2 --- /dev/null +++ b/Zend/tests/attributes/override/constants/trait_parent.phpt @@ -0,0 +1,23 @@ +--TEST-- +#[\Override]: Constants - on a trait, overrides parent class +--FILE-- + +--EXPECT-- +Done diff --git a/Zend/tests/attributes/override/constants/trait_redeclared.phpt b/Zend/tests/attributes/override/constants/trait_redeclared.phpt new file mode 100644 index 000000000000..984f9eedb668 --- /dev/null +++ b/Zend/tests/attributes/override/constants/trait_redeclared.phpt @@ -0,0 +1,21 @@ +--TEST-- +#[\Override]: Constants - trait constant redeclared, not overridden +--FILE-- + +--EXPECTF-- +Fatal error: UsesTrait::T has #[\Override] attribute, but no matching parent constant exists in %s on line %d diff --git a/Zend/tests/attributes/override/constants/trait_redeclared_interface.phpt b/Zend/tests/attributes/override/constants/trait_redeclared_interface.phpt new file mode 100644 index 000000000000..21a1aa532249 --- /dev/null +++ b/Zend/tests/attributes/override/constants/trait_redeclared_interface.phpt @@ -0,0 +1,25 @@ +--TEST-- +#[\Override]: Constants - trait constant redeclared, overrides interface +--FILE-- + +--EXPECT-- +Done diff --git a/Zend/tests/attributes/override/constants/trait_redeclared_parent.phpt b/Zend/tests/attributes/override/constants/trait_redeclared_parent.phpt new file mode 100644 index 000000000000..c3d1e43d2534 --- /dev/null +++ b/Zend/tests/attributes/override/constants/trait_redeclared_parent.phpt @@ -0,0 +1,25 @@ +--TEST-- +#[\Override]: Constants - trait constant redeclared, overrides parent class +--FILE-- + +--EXPECT-- +Done diff --git a/Zend/tests/attributes/override/constants/trait_unused.phpt b/Zend/tests/attributes/override/constants/trait_unused.phpt new file mode 100644 index 000000000000..785f2888e90b --- /dev/null +++ b/Zend/tests/attributes/override/constants/trait_unused.phpt @@ -0,0 +1,15 @@ +--TEST-- +#[\Override]: Constants - on a trait, unused +--FILE-- + +--EXPECT-- +Done diff --git a/Zend/tests/attributes/override/constants/visibility_01.phpt b/Zend/tests/attributes/override/constants/visibility_01.phpt new file mode 100644 index 000000000000..49671471f758 --- /dev/null +++ b/Zend/tests/attributes/override/constants/visibility_01.phpt @@ -0,0 +1,19 @@ +--TEST-- +#[\Override]: Constants - private constant not overridden (by public constant) +--FILE-- + +--EXPECTF-- +Fatal error: Child::C has #[\Override] attribute, but no matching parent constant exists in %s on line %d diff --git a/Zend/tests/attributes/override/constants/visibility_02.phpt b/Zend/tests/attributes/override/constants/visibility_02.phpt new file mode 100644 index 000000000000..c160a29a6180 --- /dev/null +++ b/Zend/tests/attributes/override/constants/visibility_02.phpt @@ -0,0 +1,19 @@ +--TEST-- +#[\Override]: Constants - private constant not overridden (by private constant) +--FILE-- + +--EXPECTF-- +Fatal error: Child::C has #[\Override] attribute, but no matching parent constant exists in %s on line %d diff --git a/Zend/tests/attributes/override/constants/visibility_03.phpt b/Zend/tests/attributes/override/constants/visibility_03.phpt new file mode 100644 index 000000000000..db460f24375e --- /dev/null +++ b/Zend/tests/attributes/override/constants/visibility_03.phpt @@ -0,0 +1,19 @@ +--TEST-- +#[\Override]: Constants - protected constant is overridden (by public constant) +--FILE-- + +--EXPECT-- +Done diff --git a/Zend/tests/attributes/override/constants/visibility_04.phpt b/Zend/tests/attributes/override/constants/visibility_04.phpt new file mode 100644 index 000000000000..0ad46b022f43 --- /dev/null +++ b/Zend/tests/attributes/override/constants/visibility_04.phpt @@ -0,0 +1,19 @@ +--TEST-- +#[\Override]: Constants - protected constant is overridden (by protected constant) +--FILE-- + +--EXPECT-- +Done diff --git a/Zend/zend_attributes.stub.php b/Zend/zend_attributes.stub.php index ded9c89593a3..05fd285d5b9f 100644 --- a/Zend/zend_attributes.stub.php +++ b/Zend/zend_attributes.stub.php @@ -68,7 +68,7 @@ public function __debugInfo(): array {} /** * @strict-properties */ -#[Attribute(Attribute::TARGET_METHOD|Attribute::TARGET_PROPERTY)] +#[Attribute(Attribute::TARGET_METHOD|Attribute::TARGET_PROPERTY|Attribute::TARGET_CLASS_CONSTANT)] final class Override { public function __construct() {} diff --git a/Zend/zend_attributes_arginfo.h b/Zend/zend_attributes_arginfo.h index 54a66af29966..8acac398426f 100644 --- a/Zend/zend_attributes_arginfo.h +++ b/Zend/zend_attributes_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit zend_attributes.stub.php instead. - * Stub hash: b868cb33f41d9442f42d0cec84e33fcc09f5d88c */ + * Stub hash: bae42fcb945360f90a1e2762c6c22177f25efb9e */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Attribute___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "Attribute::TARGET_ALL") @@ -230,7 +230,7 @@ static zend_class_entry *register_class_Override(void) zend_string *attribute_name_Attribute_class_Override_0 = zend_string_init_interned("Attribute", sizeof("Attribute") - 1, true); zend_attribute *attribute_Attribute_class_Override_0 = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_Override_0, 1); zend_string_release_ex(attribute_name_Attribute_class_Override_0, true); - ZVAL_LONG(&attribute_Attribute_class_Override_0->args[0].value, ZEND_ATTRIBUTE_TARGET_METHOD | ZEND_ATTRIBUTE_TARGET_PROPERTY); + ZVAL_LONG(&attribute_Attribute_class_Override_0->args[0].value, ZEND_ATTRIBUTE_TARGET_METHOD | ZEND_ATTRIBUTE_TARGET_PROPERTY | ZEND_ATTRIBUTE_TARGET_CLASS_CONST); return class_entry; } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 4c1375215888..dfe9bbf5481c 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -9370,6 +9370,14 @@ static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_as ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS; ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; } + + const zend_attribute *override = zend_get_attribute_str(c->attributes, "override", sizeof("override") - 1); + if (override) { + ZEND_CLASS_CONST_FLAGS(c) |= ZEND_ACC_OVERRIDE; + /* We need to be able to remove the flag */ + ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS; + ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; + } } } } diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 848b9d209b2d..777a8d7f4e4e 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -2115,6 +2115,10 @@ static bool do_inherit_constant_check( ); } + if (!(ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PRIVATE)) { + ZEND_CLASS_CONST_FLAGS(child_constant) &= ~ZEND_ACC_OVERRIDE; + } + if (!(ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PRIVATE) && ZEND_TYPE_IS_SET(parent_constant->type)) { inheritance_status status = class_constant_types_compatible(parent_constant, child_constant); if (status == INHERITANCE_ERROR) { @@ -2317,6 +2321,15 @@ void zend_inheritance_check_override(const zend_class_entry *ce) } } ZEND_HASH_FOREACH_END(); + ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->constants_table, zend_string *name, zend_class_constant *c) { + if (ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_OVERRIDE) { + zend_error_noreturn( + E_COMPILE_ERROR, + "%s::%s has #[\\Override] attribute, but no matching parent constant exists", + ZSTR_VAL(ce->name), ZSTR_VAL(name)); + } + } ZEND_HASH_FOREACH_END(); + ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, zend_property_info *prop) { if (prop->flags & ZEND_ACC_OVERRIDE) { zend_error_noreturn( From 99ed774c34f0ade7e5703840114081420d3bfddd Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Thu, 13 Nov 2025 20:29:32 -0800 Subject: [PATCH 2/9] Only on exact class --- Zend/zend_inheritance.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 777a8d7f4e4e..583b10d34188 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -2116,7 +2116,9 @@ static bool do_inherit_constant_check( } if (!(ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PRIVATE)) { - ZEND_CLASS_CONST_FLAGS(child_constant) &= ~ZEND_ACC_OVERRIDE; + if (child_constant->ce == ce) { + ZEND_CLASS_CONST_FLAGS(child_constant) &= ~ZEND_ACC_OVERRIDE; + } } if (!(ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PRIVATE) && ZEND_TYPE_IS_SET(parent_constant->type)) { From 6040db35bba579cccae46cb0657cbfcd66c61256 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Fri, 13 Mar 2026 18:29:57 -0700 Subject: [PATCH 3/9] Tests for enums --- .../attributes/override/constants/basic.phpt | 5 +++++ .../override/constants/enum_failure.phpt | 15 +++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 Zend/tests/attributes/override/constants/enum_failure.phpt diff --git a/Zend/tests/attributes/override/constants/basic.phpt b/Zend/tests/attributes/override/constants/basic.phpt index 4453ef0a787d..79ca6e50f100 100644 --- a/Zend/tests/attributes/override/constants/basic.phpt +++ b/Zend/tests/attributes/override/constants/basic.phpt @@ -32,6 +32,11 @@ class C extends PP implements I { public const C = 'C'; } +enum E implements I { + #[\Override] + public const I = 'I'; +} + echo "Done"; ?> diff --git a/Zend/tests/attributes/override/constants/enum_failure.phpt b/Zend/tests/attributes/override/constants/enum_failure.phpt new file mode 100644 index 000000000000..3c505be265b4 --- /dev/null +++ b/Zend/tests/attributes/override/constants/enum_failure.phpt @@ -0,0 +1,15 @@ +--TEST-- +#[\Override]: Constants - no interface for enum +--FILE-- + +--EXPECTF-- +Fatal error: Demo::C has #[\Override] attribute, but no matching parent constant exists in %s on line %d From 54f1973c534c2844696a60bb45e0588408e4cc43 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Sat, 18 Apr 2026 18:08:31 -0700 Subject: [PATCH 4/9] Enum cases override interface constants --- .../with_Override_error_enum_case.phpt | 15 +++++++++++++++ .../attributes/override/constants/basic.phpt | 5 +++++ .../override/constants/enum_failure_case.phpt | 15 +++++++++++++++ Zend/zend_compile.c | 8 ++++++++ 4 files changed, 43 insertions(+) create mode 100644 Zend/tests/attributes/delayed_target_validation/with_Override_error_enum_case.phpt create mode 100644 Zend/tests/attributes/override/constants/enum_failure_case.phpt diff --git a/Zend/tests/attributes/delayed_target_validation/with_Override_error_enum_case.phpt b/Zend/tests/attributes/delayed_target_validation/with_Override_error_enum_case.phpt new file mode 100644 index 000000000000..53d75412a849 --- /dev/null +++ b/Zend/tests/attributes/delayed_target_validation/with_Override_error_enum_case.phpt @@ -0,0 +1,15 @@ +--TEST-- +#[\DelayedTargetValidation] with #[\Override]: non-overrides still error (enum case) +--FILE-- + +--EXPECTF-- +Fatal error: DemoEnum::MyCase has #[\Override] attribute, but no matching parent constant exists in %s on line %d diff --git a/Zend/tests/attributes/override/constants/basic.phpt b/Zend/tests/attributes/override/constants/basic.phpt index 79ca6e50f100..84626b38ffd7 100644 --- a/Zend/tests/attributes/override/constants/basic.phpt +++ b/Zend/tests/attributes/override/constants/basic.phpt @@ -37,6 +37,11 @@ enum E implements I { public const I = 'I'; } +enum WithCase implements I { + #[\Override] + case I; +} + echo "Done"; ?> diff --git a/Zend/tests/attributes/override/constants/enum_failure_case.phpt b/Zend/tests/attributes/override/constants/enum_failure_case.phpt new file mode 100644 index 000000000000..1734a495d2b3 --- /dev/null +++ b/Zend/tests/attributes/override/constants/enum_failure_case.phpt @@ -0,0 +1,15 @@ +--TEST-- +#[\Override]: Constants - no interface for enum +--FILE-- + +--EXPECTF-- +Fatal error: Demo::C has #[\Override] attribute, but no matching parent constant exists in %s on line %d diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index dfe9bbf5481c..517302fd534e 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -9837,6 +9837,14 @@ static void zend_compile_enum_case(zend_ast *ast) if (deprecated) { ZEND_CLASS_CONST_FLAGS(c) |= ZEND_ACC_DEPRECATED; } + + const zend_attribute *override = zend_get_attribute_str(c->attributes, "override", sizeof("override") - 1); + if (override) { + ZEND_CLASS_CONST_FLAGS(c) |= ZEND_ACC_OVERRIDE; + /* We need to be able to remove the flag */ + enum_class->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS; + enum_class->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; + } } } From 9e5d7d61b5313785833478cb3ada62c9c1576b7d Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Fri, 8 May 2026 14:20:43 -0700 Subject: [PATCH 5/9] Clarify test names --- Zend/tests/attributes/override/constants/enum_failure.phpt | 2 +- Zend/tests/attributes/override/constants/enum_failure_case.phpt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Zend/tests/attributes/override/constants/enum_failure.phpt b/Zend/tests/attributes/override/constants/enum_failure.phpt index 3c505be265b4..77ba225e9b9e 100644 --- a/Zend/tests/attributes/override/constants/enum_failure.phpt +++ b/Zend/tests/attributes/override/constants/enum_failure.phpt @@ -1,5 +1,5 @@ --TEST-- -#[\Override]: Constants - no interface for enum +#[\Override]: Constants - no interface for enum constant --FILE-- Date: Mon, 29 Jun 2026 10:00:35 -0700 Subject: [PATCH 6/9] Expand basic tests --- Zend/tests/attributes/override/constants/basic.phpt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Zend/tests/attributes/override/constants/basic.phpt b/Zend/tests/attributes/override/constants/basic.phpt index 84626b38ffd7..c89007022051 100644 --- a/Zend/tests/attributes/override/constants/basic.phpt +++ b/Zend/tests/attributes/override/constants/basic.phpt @@ -15,12 +15,16 @@ interface II extends I { class P { public const C1 = 'C1'; public const C2 = 'C2'; + public const C3 = 'C3'; + public const C4 = 'C4'; } class PP extends P { #[\Override] public const C1 = 'C1'; public const C2 = 'C2'; + #[\Override] + public const C3 = 'C3'; } class C extends PP implements I { @@ -28,7 +32,11 @@ class C extends PP implements I { public const I = 'I'; #[\Override] public const C1 = 'C1'; + #[\Override] public const C2 = 'C2'; + public const C3 = 'C3'; + #[\Override] + public const C4 = 'C4'; public const C = 'C'; } From a58ab614f2eecf5d60fd7653069cf2a3224bc675 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Tue, 30 Jun 2026 08:36:35 -0700 Subject: [PATCH 7/9] Clarify comment --- Zend/zend_compile.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 517302fd534e..24463a191498 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -9374,7 +9374,8 @@ static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_as const zend_attribute *override = zend_get_attribute_str(c->attributes, "override", sizeof("override") - 1); if (override) { ZEND_CLASS_CONST_FLAGS(c) |= ZEND_ACC_OVERRIDE; - /* We need to be able to remove the flag */ + /* We need to be able to remove the flag once the override is + * resolved. See ZEND_ACC_DEPRECATED above. */ ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS; ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; } From f39165acc77de8e3ead2449f37409219f0c389c8 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Tue, 30 Jun 2026 08:40:01 -0700 Subject: [PATCH 8/9] Another comment --- Zend/zend_compile.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 24463a191498..c75333e6d3c5 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -9842,7 +9842,9 @@ static void zend_compile_enum_case(zend_ast *ast) const zend_attribute *override = zend_get_attribute_str(c->attributes, "override", sizeof("override") - 1); if (override) { ZEND_CLASS_CONST_FLAGS(c) |= ZEND_ACC_OVERRIDE; - /* We need to be able to remove the flag */ + /* We need to be able to remove the flag once the override is + * resolved. See ZEND_ACC_DEPRECATED handling in + * zend_compile_class_const_decl(). */ enum_class->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS; enum_class->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; } From aedaf7bd1e022578e792b1aadeeac56ecf7d6bed Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Fri, 3 Jul 2026 12:13:02 -0700 Subject: [PATCH 9/9] UPGRADING --- UPGRADING | 2 ++ 1 file changed, 2 insertions(+) diff --git a/UPGRADING b/UPGRADING index a42d5ec355a6..b9c659ccc405 100644 --- a/UPGRADING +++ b/UPGRADING @@ -215,6 +215,8 @@ PHP 8.6 UPGRADE NOTES needing to be present beforehand. . It is now possible to define the __debugInfo() magic method on enums. RFC: https://wiki.php.net/rfc/debugable-enums + . #[\Override] can now be applied to class constants, including enum cases. + RFC: https://wiki.php.net/rfc/override_constants - Curl: . curl_getinfo() return array now includes a new size_delivered key, which