Skip to content

Commit 96b98b2

Browse files
committed
Add support for final constants
1 parent c94bb37 commit 96b98b2

File tree

11 files changed

+115
-14
lines changed

11 files changed

+115
-14
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--TEST--
2+
Class constants support the final modifier
3+
--FILE--
4+
<?php
5+
6+
class Foo
7+
{
8+
final const A = "foo";
9+
final public const B = "foo";
10+
}
11+
12+
?>
13+
--EXPECT--
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Final class constants cannot be overridden
3+
--FILE--
4+
<?php
5+
6+
class Foo
7+
{
8+
final const A = "foo";
9+
}
10+
11+
class Bar extends Foo
12+
{
13+
const A = "bar";
14+
}
15+
16+
?>
17+
--EXPECTF--
18+
Fatal error: Bar::A cannot override final constant Foo::A in %s on line %d
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--TEST--
2+
Private class constants cannot be final
3+
--FILE--
4+
<?php
5+
6+
class Foo
7+
{
8+
private final const A = "foo";
9+
}
10+
11+
?>
12+
--EXPECTF--
13+
Fatal error: Private constant Foo::A cannot be final as it is never overridden in %s on line %d

Zend/tests/errmsg_038.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ class test {
1010
echo "Done\n";
1111
?>
1212
--EXPECTF--
13-
Fatal error: Cannot declare property test::$var final, the final modifier is allowed only for methods and classes in %s on line %d
13+
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

Zend/zend_compile.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7196,7 +7196,7 @@ void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t flags, z
71967196

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

@@ -7284,10 +7284,17 @@ void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_ast *attr
72847284
zend_string *doc_comment = doc_comment_ast ? zend_string_copy(zend_ast_get_str(doc_comment_ast)) : NULL;
72857285
zval value_zv;
72867286

7287-
if (UNEXPECTED(flags & (ZEND_ACC_STATIC|ZEND_ACC_ABSTRACT|ZEND_ACC_FINAL))) {
7287+
if (UNEXPECTED(flags & (ZEND_ACC_STATIC|ZEND_ACC_ABSTRACT))) {
72887288
zend_check_const_and_trait_alias_attr(flags, "constant");
72897289
}
72907290

7291+
if (UNEXPECTED((flags & ZEND_ACC_PRIVATE) && (flags & ZEND_ACC_FINAL))) {
7292+
zend_error_noreturn(
7293+
E_COMPILE_ERROR, "Private constant %s::%s cannot be final as it is never overridden",
7294+
ZSTR_VAL(ce->name), ZSTR_VAL(name)
7295+
);
7296+
}
7297+
72917298
zend_const_expr_to_zval(&value_zv, value_ast_ptr);
72927299
c = zend_declare_class_constant_ex(ce, name, &value_zv, flags, doc_comment);
72937300

Zend/zend_inheritance.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,6 +1180,13 @@ static void do_inherit_class_constant(zend_string *name, zend_class_constant *pa
11801180
zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s must be %s (as in class %s)%s",
11811181
ZSTR_VAL(ce->name), ZSTR_VAL(name), zend_visibility_string(ZEND_CLASS_CONST_FLAGS(parent_const)), ZSTR_VAL(parent_const->ce->name), (ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PUBLIC) ? "" : " or weaker");
11821182
}
1183+
1184+
if (UNEXPECTED((ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_FINAL))) {
1185+
zend_error_noreturn(
1186+
E_COMPILE_ERROR, "%s::%s cannot override final constant %s::%s",
1187+
ZSTR_VAL(ce->name), ZSTR_VAL(name), ZSTR_VAL(parent_const->ce->name), ZSTR_VAL(name)
1188+
);
1189+
}
11831190
} else if (!(ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE)) {
11841191
if (Z_TYPE(parent_const->value) == IS_CONSTANT_AST) {
11851192
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;

ext/reflection/php_reflection.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3699,6 +3699,12 @@ ZEND_METHOD(ReflectionClassConstant, isProtected)
36993699
}
37003700
/* }}} */
37013701

3702+
/* Returns whether this constant is final */
3703+
ZEND_METHOD(ReflectionClassConstant, isFinal)
3704+
{
3705+
_class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL);
3706+
}
3707+
37023708
/* {{{ Returns a bitfield of the access modifiers for this constant */
37033709
ZEND_METHOD(ReflectionClassConstant, getModifiers)
37043710
{

ext/reflection/php_reflection.stub.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,8 @@ public function isPrivate() {}
470470
/** @return bool */
471471
public function isProtected() {}
472472

473+
public function isFinal(): bool {}
474+
473475
/** @return int */
474476
public function getModifiers() {}
475477

ext/reflection/php_reflection_arginfo.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: 47ac64b027cdeb0e9996147277f79fa9d6b876bd */
2+
* Stub hash: 4c8d4c90acbbfad72e673c0745dc251625638b53 */
33

44
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 0, 1)
55
ZEND_ARG_TYPE_INFO(0, modifiers, IS_LONG, 0)
@@ -350,6 +350,8 @@ ZEND_END_ARG_INFO()
350350

351351
#define arginfo_class_ReflectionClassConstant_isProtected arginfo_class_ReflectionFunctionAbstract_inNamespace
352352

353+
#define arginfo_class_ReflectionClassConstant_isFinal arginfo_class_ReflectionClass_isEnum
354+
353355
#define arginfo_class_ReflectionClassConstant_getModifiers arginfo_class_ReflectionFunctionAbstract_inNamespace
354356

355357
#define arginfo_class_ReflectionClassConstant_getDeclaringClass arginfo_class_ReflectionFunctionAbstract_inNamespace
@@ -682,6 +684,7 @@ ZEND_METHOD(ReflectionClassConstant, getValue);
682684
ZEND_METHOD(ReflectionClassConstant, isPublic);
683685
ZEND_METHOD(ReflectionClassConstant, isPrivate);
684686
ZEND_METHOD(ReflectionClassConstant, isProtected);
687+
ZEND_METHOD(ReflectionClassConstant, isFinal);
685688
ZEND_METHOD(ReflectionClassConstant, getModifiers);
686689
ZEND_METHOD(ReflectionClassConstant, getDeclaringClass);
687690
ZEND_METHOD(ReflectionClassConstant, getDocComment);
@@ -957,6 +960,7 @@ static const zend_function_entry class_ReflectionClassConstant_methods[] = {
957960
ZEND_ME(ReflectionClassConstant, isPublic, arginfo_class_ReflectionClassConstant_isPublic, ZEND_ACC_PUBLIC)
958961
ZEND_ME(ReflectionClassConstant, isPrivate, arginfo_class_ReflectionClassConstant_isPrivate, ZEND_ACC_PUBLIC)
959962
ZEND_ME(ReflectionClassConstant, isProtected, arginfo_class_ReflectionClassConstant_isProtected, ZEND_ACC_PUBLIC)
963+
ZEND_ME(ReflectionClassConstant, isFinal, arginfo_class_ReflectionClassConstant_isFinal, ZEND_ACC_PUBLIC)
960964
ZEND_ME(ReflectionClassConstant, getModifiers, arginfo_class_ReflectionClassConstant_getModifiers, ZEND_ACC_PUBLIC)
961965
ZEND_ME(ReflectionClassConstant, getDeclaringClass, arginfo_class_ReflectionClassConstant_getDeclaringClass, ZEND_ACC_PUBLIC)
962966
ZEND_ME(ReflectionClassConstant, getDocComment, arginfo_class_ReflectionClassConstant_getDocComment, ZEND_ACC_PUBLIC)

ext/reflection/tests/ReflectionClassConstant_basic1.phpt

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ function reflectClassConstant($base, $constant) {
2020
var_dump($constInfo->isPrivate());
2121
echo "isProtected():\n";
2222
var_dump($constInfo->isProtected());
23+
echo "isFinal():\n";
24+
var_dump($constInfo->isFinal());
2325
echo "getModifiers():\n";
2426
var_dump($constInfo->getModifiers());
2527
echo "getDeclaringClass():\n";
@@ -34,12 +36,14 @@ class TestClass {
3436
/** Another doc comment */
3537
protected const PROT = 4;
3638
private const PRIV = "keepOut";
39+
public final const FINAL = "foo";
3740
}
3841
$instance = new TestClass();
3942

4043
reflectClassConstant("TestClass", "PUB");
4144
reflectClassConstant("TestClass", "PROT");
4245
reflectClassConstant("TestClass", "PRIV");
46+
reflectClassConstant("TestClass", "FINAL");
4347
reflectClassConstant($instance, "PRIV");
4448
reflectClassConstant($instance, "BAD_CONST");
4549

@@ -61,6 +65,8 @@ isPrivate():
6165
bool(false)
6266
isProtected():
6367
bool(false)
68+
isFinal():
69+
bool(false)
6470
getModifiers():
6571
int(1)
6672
getDeclaringClass():
@@ -88,6 +94,8 @@ isPrivate():
8894
bool(false)
8995
isProtected():
9096
bool(true)
97+
isFinal():
98+
bool(false)
9199
getModifiers():
92100
int(2)
93101
getDeclaringClass():
@@ -115,6 +123,8 @@ isPrivate():
115123
bool(true)
116124
isProtected():
117125
bool(false)
126+
isFinal():
127+
bool(false)
118128
getModifiers():
119129
int(4)
120130
getDeclaringClass():
@@ -125,6 +135,35 @@ object(ReflectionClass)#3 (1) {
125135
getDocComment():
126136
bool(false)
127137

138+
**********************************
139+
**********************************
140+
Reflecting on class constant TestClass::FINAL
141+
142+
__toString():
143+
string(41) "Constant [ public string FINAL ] { foo }
144+
"
145+
getName():
146+
string(5) "FINAL"
147+
getValue():
148+
string(3) "foo"
149+
isPublic():
150+
bool(true)
151+
isPrivate():
152+
bool(false)
153+
isProtected():
154+
bool(false)
155+
isFinal():
156+
bool(true)
157+
getModifiers():
158+
int(33)
159+
getDeclaringClass():
160+
object(ReflectionClass)#3 (1) {
161+
["name"]=>
162+
string(9) "TestClass"
163+
}
164+
getDocComment():
165+
bool(false)
166+
128167
**********************************
129168
**********************************
130169
Reflecting on class constant TestClass::PRIV
@@ -142,6 +181,8 @@ isPrivate():
142181
bool(true)
143182
isProtected():
144183
bool(false)
184+
isFinal():
185+
bool(false)
145186
getModifiers():
146187
int(4)
147188
getDeclaringClass():

0 commit comments

Comments
 (0)