Skip to content

Commit e8a05c4

Browse files
committed
Properly check visibility/staticness and allow abstract private
1 parent d23f69a commit e8a05c4

File tree

7 files changed

+65
-8
lines changed

7 files changed

+65
-8
lines changed

Zend/tests/traits/abstract_method_1.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ Abstract method from trait enforced in class
44
<?php
55

66
trait T {
7-
abstract function neededByTheTrait(int $a, string $b);
7+
abstract public function neededByTheTrait(int $a, string $b);
88
}
99

1010
class C {
1111
use T;
1212

13-
function neededByTheTrait(array $a, object $b) {}
13+
public function neededByTheTrait(array $a, object $b) {}
1414
}
1515

1616
?>

Zend/tests/traits/abstract_method_2.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ trait T2 {
1313
class C {
1414
use T1, T2;
1515

16-
function test(): int {}
16+
public function test(): int {}
1717
}
1818

1919
?>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Private abstract method from trait enforced in class
3+
--FILE--
4+
<?php
5+
6+
trait T {
7+
abstract private function neededByTheTrait(int $a, string $b);
8+
}
9+
10+
class C {
11+
use T;
12+
13+
private function neededByTheTrait(array $a, object $b) {}
14+
}
15+
16+
?>
17+
--EXPECTF--
18+
Fatal error: Declaration of C::neededByTheTrait(array $a, object $b) must be compatible with T::neededByTheTrait(int $a, string $b) in %s on line %d
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Visibility enforcement on abstract trait methods
3+
--FILE--
4+
<?php
5+
6+
trait T {
7+
abstract public function method(int $a, string $b);
8+
}
9+
10+
class C {
11+
use T;
12+
13+
private function method(int $a, string $b) {}
14+
}
15+
16+
?>
17+
--EXPECTF--
18+
Fatal error: Access level to C::method() must be public (as in class T) in %s on line %d
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Staticness enforcement on abstract trait methods
3+
--FILE--
4+
<?php
5+
6+
trait T {
7+
abstract static public function method(int $a, string $b);
8+
}
9+
10+
class C {
11+
use T;
12+
13+
public function method(int $a, string $b) {}
14+
}
15+
16+
?>
17+
--EXPECTF--
18+
Fatal error: Cannot make static method T::method() non static in class C in %s on line %d

Zend/zend_compile.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6023,7 +6023,7 @@ void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_boo
60236023
}
60246024

60256025
if (op_array->fn_flags & ZEND_ACC_ABSTRACT) {
6026-
if (op_array->fn_flags & ZEND_ACC_PRIVATE) {
6026+
if ((op_array->fn_flags & ZEND_ACC_PRIVATE) && !(ce->ce_flags & ZEND_ACC_TRAIT)) {
60276027
zend_error_noreturn(E_COMPILE_ERROR, "%s function %s::%s() cannot be declared private",
60286028
in_interface ? "Interface" : "Abstract", ZSTR_VAL(ce->name), ZSTR_VAL(name));
60296029
}

Zend/zend_inheritance.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -508,8 +508,10 @@ static inheritance_status zend_do_perform_implementation_check(
508508
&& ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
509509
&& (proto->common.fn_flags & ZEND_ACC_ABSTRACT) == 0)));
510510

511-
/* If the prototype method is private do not enforce a signature */
512-
ZEND_ASSERT(!(proto->common.fn_flags & ZEND_ACC_PRIVATE));
511+
/* If the prototype method is private and not abstract, we do not enforce a signature.
512+
* private abstract methods can only occur in traits. */
513+
ZEND_ASSERT(!(proto->common.fn_flags & ZEND_ACC_PRIVATE)
514+
|| (proto->common.fn_flags & ZEND_ACC_ABSTRACT));
513515

514516
/* The number of required arguments cannot increase. */
515517
if (proto->common.required_num_args < fe->common.required_num_args) {
@@ -824,7 +826,7 @@ static zend_always_inline inheritance_status do_inheritance_check_on_method_ex(z
824826
child->common.fn_flags |= ZEND_ACC_CHANGED;
825827
}
826828

827-
if (parent_flags & ZEND_ACC_PRIVATE) {
829+
if ((parent_flags & ZEND_ACC_PRIVATE) && !(parent_flags & ZEND_ACC_ABSTRACT)) {
828830
return INHERITANCE_SUCCESS;
829831
}
830832

@@ -1562,7 +1564,8 @@ static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_s
15621564

15631565
/* Abstract method signatures from the trait must be satisfied. */
15641566
if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1565-
perform_delayable_implementation_check(ce, existing_fn, fn);
1567+
do_inheritance_check_on_method(existing_fn, fn, ce, NULL);
1568+
fn->common.prototype = NULL;
15661569
return;
15671570
}
15681571

0 commit comments

Comments
 (0)