Skip to content

Commit e679ab3

Browse files
committed
Fix GH-12854: 8.3 - as final trait-used method does not correctly report visibility in Reflection
Closes GH-12857.
1 parent 8c5f625 commit e679ab3

File tree

3 files changed

+89
-4
lines changed

3 files changed

+89
-4
lines changed

NEWS

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.3.2
44

5+
- Core:
6+
. Fixed bug GH-12854 (8.3 - as final trait-used method does not correctly
7+
report visibility in Reflection). (nielsdos)
58

69
07 Dec 2023, PHP 8.3.1RC1
710

Zend/tests/traits/gh12854.phpt

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
--TEST--
2+
GH-12854 (8.3 - as final trait-used method does not correctly report visibility in Reflection)
3+
--FILE--
4+
<?php
5+
6+
trait SimpleTrait
7+
{
8+
public function pub() {}
9+
protected function prot() {}
10+
private function priv() {}
11+
12+
public final function final1() {}
13+
public final function final2() {}
14+
public final function final3() {}
15+
}
16+
17+
18+
class Test
19+
{
20+
use SimpleTrait {
21+
pub as final;
22+
prot as final;
23+
priv as final;
24+
25+
final1 as private;
26+
final2 as protected;
27+
final3 as public;
28+
}
29+
}
30+
31+
foreach (['pub', 'prot', 'priv', 'final1', 'final2', 'final3'] as $method) {
32+
echo "--- Method: $method ---\n";
33+
$rm = new ReflectionMethod(Test::class, $method);
34+
var_dump($rm->isFinal());
35+
var_dump($rm->isPublic());
36+
var_dump($rm->isProtected());
37+
var_dump($rm->isPrivate());
38+
}
39+
40+
?>
41+
--EXPECTF--
42+
Warning: Private methods cannot be final as they are never overridden by other classes in %s on line %d
43+
44+
Warning: Private methods cannot be final as they are never overridden by other classes in %s on line %d
45+
--- Method: pub ---
46+
bool(true)
47+
bool(true)
48+
bool(false)
49+
bool(false)
50+
--- Method: prot ---
51+
bool(true)
52+
bool(false)
53+
bool(true)
54+
bool(false)
55+
--- Method: priv ---
56+
bool(true)
57+
bool(false)
58+
bool(false)
59+
bool(true)
60+
--- Method: final1 ---
61+
bool(true)
62+
bool(false)
63+
bool(false)
64+
bool(true)
65+
--- Method: final2 ---
66+
bool(true)
67+
bool(false)
68+
bool(true)
69+
bool(false)
70+
--- Method: final3 ---
71+
bool(true)
72+
bool(true)
73+
bool(false)
74+
bool(false)

Zend/zend_inheritance.c

+12-4
Original file line numberDiff line numberDiff line change
@@ -1949,6 +1949,10 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_
19491949
zend_function *new_fn;
19501950
bool check_inheritance = false;
19511951

1952+
if ((fn->common.fn_flags & (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)) == (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)) {
1953+
zend_error(E_COMPILE_WARNING, "Private methods cannot be final as they are never overridden by other classes");
1954+
}
1955+
19521956
if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) {
19531957
/* if it is the same function with the same visibility and has not been assigned a class scope yet, regardless
19541958
* of where it is coming from there is no conflict and we do not need to add it again */
@@ -2048,10 +2052,10 @@ static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, z
20482052
&& zend_string_equals_ci(alias->trait_method.method_name, fnname)
20492053
) {
20502054
fn_copy = *fn;
2051-
2052-
/* if it is 0, no modifiers have been changed */
2053-
if (alias->modifiers) {
2055+
if (alias->modifiers & ZEND_ACC_PPP_MASK) {
20542056
fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2057+
} else {
2058+
fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
20552059
}
20562060

20572061
lcname = zend_string_tolower(alias->alias);
@@ -2079,7 +2083,11 @@ static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, z
20792083
&& fn->common.scope == aliases[i]
20802084
&& zend_string_equals_ci(alias->trait_method.method_name, fnname)
20812085
) {
2082-
fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2086+
if (alias->modifiers & ZEND_ACC_PPP_MASK) {
2087+
fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2088+
} else {
2089+
fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2090+
}
20832091
}
20842092
alias_ptr++;
20852093
alias = *alias_ptr;

0 commit comments

Comments
 (0)