Skip to content

Add support for final constants #6878

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Zend/tests/bug49472.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ class FooBar extends Foo implements ia {
new FooBar;

?>
--EXPECTF--
Fatal error: Cannot inherit previously-inherited or override constant c from interface ia in %s on line %d
===DONE===
--EXPECT--
===DONE===
13 changes: 13 additions & 0 deletions Zend/tests/constants/final_constants/final_const1.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
Class constants support the final modifier
--FILE--
<?php

class Foo
{
final const A = "foo";
final public const B = "foo";
}

?>
--EXPECT--
22 changes: 22 additions & 0 deletions Zend/tests/constants/final_constants/final_const10.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Interface constants inherited from other interfaces can be redeclared
--FILE--
<?php

interface I1
{
const C = 1;
}

interface I2
{
const C = 2;
}

interface I3 extends I1, I2
{
const C = 3;
}

?>
--EXPECT--
22 changes: 22 additions & 0 deletions Zend/tests/constants/final_constants/final_const11.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Class constants cannot be inherited from both a class and an interface
--FILE--
<?php

class C
{
const C = 1;
}

interface I
{
const C = 1;
}

class C2 extends C implements I
{
}

?>
--EXPECTF--
Fatal error: Class C2 inherits both C::C and I::C, which is ambiguous in %s on line %d
22 changes: 22 additions & 0 deletions Zend/tests/constants/final_constants/final_const12.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Interface constants cannot be inherited from other interfaces
--FILE--
<?php

interface I1
{
const C = 1;
}

interface I2
{
const C = 2;
}

interface I3 extends I1, I2
{
}

?>
--EXPECTF--
Fatal error: Class I3 inherits both I1::C and I2::C, which is ambiguous in %s on line %d
18 changes: 18 additions & 0 deletions Zend/tests/constants/final_constants/final_const2.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
Final class constants cannot be overridden
--FILE--
<?php

class Foo
{
final const A = "foo";
}

class Bar extends Foo
{
const A = "bar";
}

?>
--EXPECTF--
Fatal error: Bar::A cannot override final constant Foo::A in %s on line %d
13 changes: 13 additions & 0 deletions Zend/tests/constants/final_constants/final_const3.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
Private class constants cannot be final
--FILE--
<?php

class Foo
{
private final const A = "foo";
}

?>
--EXPECTF--
Fatal error: Private constant Foo::A cannot be final as it is not visible to other classes in %s on line %d
17 changes: 17 additions & 0 deletions Zend/tests/constants/final_constants/final_const4.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
Interface constants can be overridden directly
--FILE--
<?php

interface I
{
const X = 1;
}

class C implements I
{
const X = 2;
}

?>
--EXPECT--
18 changes: 18 additions & 0 deletions Zend/tests/constants/final_constants/final_const5.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
Final interface constants cannot be overridden directly
--FILE--
<?php

interface I
{
final public const X = 1;
}

class C implements I
{
const X = 2;
}

?>
--EXPECTF--
Fatal error: C::X cannot override final constant I::X in %s on line %d
16 changes: 16 additions & 0 deletions Zend/tests/constants/final_constants/final_const6.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
Final interface constants can be inherited
--FILE--
<?php

interface I
{
final public const X = 1;
}

class C implements I
{
}

?>
--EXPECT--
19 changes: 19 additions & 0 deletions Zend/tests/constants/final_constants/final_const7.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
Interface constants can be overridden indirectly
--FILE--
<?php

interface I
{
const X = 1;
}

class C implements I {}

class D extends C
{
const X = 2;
}

?>
--EXPECT--
22 changes: 22 additions & 0 deletions Zend/tests/constants/final_constants/final_const8.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Class constants cannot be inherited from two different interfaces
--FILE--
<?php

interface I1
{
const C = 1;
}

interface I2
{
const C = 1;
}

class C implements I1, I2
{
}

?>
--EXPECTF--
Fatal error: Class C inherits both I1::C and I2::C, which is ambiguous in %s on line %d
22 changes: 22 additions & 0 deletions Zend/tests/constants/final_constants/final_const9.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Class constants inherited from interfaces can be redeclared
--FILE--
<?php

interface I1
{
const C = 1;
}

interface I2
{
const C = 2;
}

class C implements I1, I2
{
const C = 3;
}

?>
--EXPECT--
2 changes: 1 addition & 1 deletion Zend/tests/errmsg_025.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ class test implements test1, test2 {
echo "Done\n";
?>
--EXPECTF--
Fatal error: Cannot inherit previously-inherited or override constant FOO from interface test2 in %s on line %d
Fatal error: Class test inherits both test1::FOO and test2::FOO, which is ambiguous in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/errmsg_038.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ class test {
echo "Done\n";
?>
--EXPECTF--
Fatal error: Cannot declare property test::$var final, the final modifier is allowed only for methods and classes in %s on line %d
Fatal error: Cannot declare property test::$var final, the final modifier is allowed only for methods, classes, and class constants in %s on line %d
18 changes: 0 additions & 18 deletions Zend/tests/inter_01.phpt

This file was deleted.

6 changes: 3 additions & 3 deletions Zend/zend_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -4331,12 +4331,12 @@ ZEND_API void zend_declare_property_stringl(zend_class_entry *ce, const char *na
}
/* }}} */

ZEND_API zend_class_constant *zend_declare_class_constant_ex(zend_class_entry *ce, zend_string *name, zval *value, int access_type, zend_string *doc_comment) /* {{{ */
ZEND_API zend_class_constant *zend_declare_class_constant_ex(zend_class_entry *ce, zend_string *name, zval *value, int flags, zend_string *doc_comment) /* {{{ */
{
zend_class_constant *c;

if (ce->ce_flags & ZEND_ACC_INTERFACE) {
if (access_type != ZEND_ACC_PUBLIC) {
if (!(flags & ZEND_ACC_PUBLIC)) {
zend_error_noreturn(E_COMPILE_ERROR, "Access type for interface constant %s::%s must be public", ZSTR_VAL(ce->name), ZSTR_VAL(name));
}
}
Expand All @@ -4356,7 +4356,7 @@ ZEND_API zend_class_constant *zend_declare_class_constant_ex(zend_class_entry *c
c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
}
ZVAL_COPY_VALUE(&c->value, value);
ZEND_CLASS_CONST_FLAGS(c) = access_type;
ZEND_CLASS_CONST_FLAGS(c) = flags;
c->doc_comment = doc_comment;
c->attributes = NULL;
c->ce = ce;
Expand Down
11 changes: 9 additions & 2 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -7270,7 +7270,7 @@ void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t flags, z

if (flags & ZEND_ACC_FINAL) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare property %s::$%s final, "
"the final modifier is allowed only for methods and classes",
"the final modifier is allowed only for methods, classes, and class constants",
ZSTR_VAL(ce->name), ZSTR_VAL(name));
}

Expand Down Expand Up @@ -7358,10 +7358,17 @@ void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_ast *attr
zend_string *doc_comment = doc_comment_ast ? zend_string_copy(zend_ast_get_str(doc_comment_ast)) : NULL;
zval value_zv;

if (UNEXPECTED(flags & (ZEND_ACC_STATIC|ZEND_ACC_ABSTRACT|ZEND_ACC_FINAL))) {
if (UNEXPECTED(flags & (ZEND_ACC_STATIC|ZEND_ACC_ABSTRACT))) {
zend_check_const_and_trait_alias_attr(flags, "constant");
}

if (UNEXPECTED((flags & ZEND_ACC_PRIVATE) && (flags & ZEND_ACC_FINAL))) {
zend_error_noreturn(
E_COMPILE_ERROR, "Private constant %s::%s cannot be final as it is not visible to other classes",
ZSTR_VAL(ce->name), ZSTR_VAL(name)
);
}

zend_const_expr_to_zval(&value_zv, value_ast_ptr);
c = zend_declare_class_constant_ex(ce, name, &value_zv, flags, doc_comment);

Expand Down
Loading