Skip to content

Commit

Permalink
Fix GH-12854: 8.3 - as final trait-used method does not correctly rep…
Browse files Browse the repository at this point in the history
…ort visibility in Reflection

Closes GH-12857.
  • Loading branch information
nielsdos committed Dec 5, 2023
1 parent 8c5f625 commit e679ab3
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 4 deletions.
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 8.3.2

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

07 Dec 2023, PHP 8.3.1RC1

Expand Down
74 changes: 74 additions & 0 deletions Zend/tests/traits/gh12854.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
--TEST--
GH-12854 (8.3 - as final trait-used method does not correctly report visibility in Reflection)
--FILE--
<?php

trait SimpleTrait
{
public function pub() {}
protected function prot() {}
private function priv() {}

public final function final1() {}
public final function final2() {}
public final function final3() {}
}


class Test
{
use SimpleTrait {
pub as final;
prot as final;
priv as final;

final1 as private;
final2 as protected;
final3 as public;
}
}

foreach (['pub', 'prot', 'priv', 'final1', 'final2', 'final3'] as $method) {
echo "--- Method: $method ---\n";
$rm = new ReflectionMethod(Test::class, $method);
var_dump($rm->isFinal());
var_dump($rm->isPublic());
var_dump($rm->isProtected());
var_dump($rm->isPrivate());
}

?>
--EXPECTF--
Warning: Private methods cannot be final as they are never overridden by other classes in %s on line %d

Warning: Private methods cannot be final as they are never overridden by other classes in %s on line %d
--- Method: pub ---
bool(true)
bool(true)
bool(false)
bool(false)
--- Method: prot ---
bool(true)
bool(false)
bool(true)
bool(false)
--- Method: priv ---
bool(true)
bool(false)
bool(false)
bool(true)
--- Method: final1 ---
bool(true)
bool(false)
bool(false)
bool(true)
--- Method: final2 ---
bool(true)
bool(false)
bool(true)
bool(false)
--- Method: final3 ---
bool(true)
bool(true)
bool(false)
bool(false)
16 changes: 12 additions & 4 deletions Zend/zend_inheritance.c
Original file line number Diff line number Diff line change
Expand Up @@ -1949,6 +1949,10 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_
zend_function *new_fn;
bool check_inheritance = false;

if ((fn->common.fn_flags & (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)) == (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)) {
zend_error(E_COMPILE_WARNING, "Private methods cannot be final as they are never overridden by other classes");
}

if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) {
/* if it is the same function with the same visibility and has not been assigned a class scope yet, regardless
* of where it is coming from there is no conflict and we do not need to add it again */
Expand Down Expand Up @@ -2048,10 +2052,10 @@ static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, z
&& zend_string_equals_ci(alias->trait_method.method_name, fnname)
) {
fn_copy = *fn;

/* if it is 0, no modifiers have been changed */
if (alias->modifiers) {
if (alias->modifiers & ZEND_ACC_PPP_MASK) {
fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
} else {
fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
}

lcname = zend_string_tolower(alias->alias);
Expand Down Expand Up @@ -2079,7 +2083,11 @@ static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, z
&& fn->common.scope == aliases[i]
&& zend_string_equals_ci(alias->trait_method.method_name, fnname)
) {
fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
if (alias->modifiers & ZEND_ACC_PPP_MASK) {
fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
} else {
fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
}
}
alias_ptr++;
alias = *alias_ptr;
Expand Down

0 comments on commit e679ab3

Please sign in to comment.