Skip to content

Commit ad6d15a

Browse files
[RFC] Final Property Promotion
https://wiki.php.net/rfc/final_promotion
1 parent 58968f6 commit ad6d15a

8 files changed

+82
-8
lines changed

UPGRADING

+2
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ PHP 8.5 UPGRADE NOTES
106106
. Fatal Errors (such as an exceeded maximum execution time) now include a
107107
backtrace.
108108
RFC: https://wiki.php.net/rfc/error_backtraces_v2
109+
. Constructor property promotion can now be used for final properties.
110+
RFC: https://wiki.php.net/rfc/final_promotion
109111

110112
- Curl:
111113
. Added support for share handles that are persisted across multiple PHP
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Promoted property may be marked final (hook)
3+
--FILE--
4+
<?php
5+
6+
class A {
7+
public function __construct(
8+
public final $prop { get {} set {} }
9+
) {}
10+
}
11+
12+
class B extends A {
13+
public $prop { get {} set {} }
14+
}
15+
16+
?>
17+
--EXPECTF--
18+
Fatal error: Cannot override final property A::$prop in %s on line %d
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Promoted property may be marked final (normal)
3+
--FILE--
4+
<?php
5+
6+
class A {
7+
public function __construct(
8+
public final $prop
9+
) {}
10+
}
11+
12+
class B extends A {
13+
public $prop { get {} set {} }
14+
}
15+
16+
?>
17+
--EXPECTF--
18+
Fatal error: Cannot override final property A::$prop in %s on line %d
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Promoted property may be marked final (no visibility needed)
3+
--FILE--
4+
<?php
5+
6+
class A {
7+
public function __construct(
8+
final $prop
9+
) {}
10+
}
11+
12+
class B extends A {
13+
public $prop { get {} set {} }
14+
}
15+
16+
?>
17+
--EXPECTF--
18+
Fatal error: Cannot override final property A::$prop in %s on line %d
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Confirm that the AST indicates final promoted properties
3+
--FILE--
4+
<?php
5+
try {
6+
assert(false && new class {
7+
public function __construct( public final $prop ) {}
8+
});
9+
} catch (Error $e) {
10+
echo $e->getMessage(), "\n";
11+
}
12+
?>
13+
--EXPECT--
14+
assert(false && new class {
15+
public function __construct(public final $prop) {
16+
}
17+
18+
})

Zend/zend_ast.c

+3
Original file line numberDiff line numberDiff line change
@@ -2721,6 +2721,9 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
27212721
zend_ast_export_attributes(str, ast->child[3], indent, 0);
27222722
}
27232723
zend_ast_export_visibility(str, ast->attr, ZEND_MODIFIER_TARGET_CPP);
2724+
if (ast->attr & ZEND_ACC_FINAL) {
2725+
smart_str_appends(str, "final ");
2726+
}
27242727
if (ast->child[0]) {
27252728
zend_ast_export_type(str, ast->child[0], indent);
27262729
smart_str_appendc(str, ' ');

Zend/zend_compile.c

+2-8
Original file line numberDiff line numberDiff line change
@@ -903,13 +903,7 @@ uint32_t zend_modifier_token_to_flag(zend_modifier_target target, uint32_t token
903903
}
904904
break;
905905
case T_FINAL:
906-
if (target == ZEND_MODIFIER_TARGET_METHOD
907-
|| target == ZEND_MODIFIER_TARGET_CONSTANT
908-
|| target == ZEND_MODIFIER_TARGET_PROPERTY
909-
|| target == ZEND_MODIFIER_TARGET_PROPERTY_HOOK) {
910-
return ZEND_ACC_FINAL;
911-
}
912-
break;
906+
return ZEND_ACC_FINAL;
913907
case T_STATIC:
914908
if (target == ZEND_MODIFIER_TARGET_PROPERTY || target == ZEND_MODIFIER_TARGET_METHOD) {
915909
return ZEND_ACC_STATIC;
@@ -7622,7 +7616,7 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32
76227616
zend_string *name = zval_make_interned_string(zend_ast_get_zval(var_ast));
76237617
bool is_ref = (param_ast->attr & ZEND_PARAM_REF) != 0;
76247618
bool is_variadic = (param_ast->attr & ZEND_PARAM_VARIADIC) != 0;
7625-
uint32_t property_flags = param_ast->attr & (ZEND_ACC_PPP_MASK | ZEND_ACC_PPP_SET_MASK | ZEND_ACC_READONLY);
7619+
uint32_t property_flags = param_ast->attr & (ZEND_ACC_PPP_MASK | ZEND_ACC_PPP_SET_MASK | ZEND_ACC_READONLY | ZEND_ACC_FINAL);
76267620
bool is_promoted = property_flags || hooks_ast;
76277621

76287622
znode var_node, default_node;

ext/reflection/tests/ReflectionProperty_isFinal.phpt

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ class C {
1212
public protected(set) final mixed $p6;
1313
public private(set) mixed $p7;
1414
public private(set) final mixed $p8;
15+
16+
public function __construct( final $p9 ) {}
1517
}
1618

1719
$rc = new ReflectionClass(C::class);
@@ -30,3 +32,4 @@ p5: bool(false)
3032
p6: bool(true)
3133
p7: bool(true)
3234
p8: bool(true)
35+
p9: bool(true)

0 commit comments

Comments
 (0)