Skip to content

Commit 8576e9e

Browse files
committed
Check abstract method signatures coming from traits
1 parent 0a9bdd6 commit 8576e9e

File tree

5 files changed

+54
-43
lines changed

5 files changed

+54
-43
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Abstract method from trait enforced in class
3+
--FILE--
4+
<?php
5+
6+
trait T {
7+
abstract function neededByTheTrait(int $a, string $b);
8+
}
9+
10+
class C {
11+
use T;
12+
13+
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: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
Mutually incompatible methods from traits are fine as long as the final method is compatible
3+
--FILE--
4+
<?php
5+
6+
trait T1 {
7+
abstract public function test();
8+
}
9+
trait T2 {
10+
abstract public function test(): int;
11+
}
12+
13+
class C {
14+
use T1, T2;
15+
16+
function test(): int {}
17+
}
18+
19+
?>
20+
===DONE===
21+
--EXPECT--
22+
===DONE===

Zend/tests/traits/bug60217b.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ class CBroken {
2222
$o = new CBroken;
2323
$o->foo(1);
2424
--EXPECTF--
25-
Fatal error: Declaration of TBroken1::foo($a) must be compatible with TBroken2::foo($a, $b = 0) in %s
25+
Fatal error: Declaration of CBroken::foo($a) must be compatible with TBroken2::foo($a, $b = 0) in %s on line %d

Zend/tests/traits/bug60217c.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ class CBroken {
2222
$o = new CBroken;
2323
$o->foo(1);
2424
--EXPECTF--
25-
Fatal error: Declaration of TBroken2::foo($a) must be compatible with TBroken1::foo($a, $b = 0) in %s on line %d
25+
Fatal error: Declaration of CBroken::foo($a) must be compatible with TBroken1::foo($a, $b = 0) in %s on line %d

Zend/zend_inheritance.c

Lines changed: 12 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,6 @@ static void add_property_compatibility_obligation(
3434
zend_class_entry *ce, const zend_property_info *child_prop,
3535
const zend_property_info *parent_prop);
3636

37-
static void overridden_ptr_dtor(zval *zv) /* {{{ */
38-
{
39-
efree_size(Z_PTR_P(zv), sizeof(zend_function));
40-
}
41-
/* }}} */
42-
4337
static void zend_type_copy_ctor(zend_type *type, zend_bool persistent) {
4438
if (ZEND_TYPE_HAS_LIST(*type)) {
4539
zend_type_list *old_list = ZEND_TYPE_LIST(*type);
@@ -1571,7 +1565,7 @@ static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zen
15711565
}
15721566
/* }}} */
15731567

1574-
static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_string *key, zend_function *fn, HashTable **overridden) /* {{{ */
1568+
static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_string *key, zend_function *fn) /* {{{ */
15751569
{
15761570
zend_function *existing_fn = NULL;
15771571
zend_function *new_fn;
@@ -1585,31 +1579,14 @@ static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_s
15851579
return;
15861580
}
15871581

1582+
/* Abstract method signatures from the trait must be satisfied. */
1583+
if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1584+
perform_delayable_implementation_check(ce, existing_fn, fn);
1585+
return;
1586+
}
1587+
15881588
if (existing_fn->common.scope == ce) {
15891589
/* members from the current class override trait methods */
1590-
/* use temporary *overridden HashTable to detect hidden conflict */
1591-
if (*overridden) {
1592-
if ((existing_fn = zend_hash_find_ptr(*overridden, key)) != NULL) {
1593-
if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1594-
/* Make sure the trait method is compatible with previosly declared abstract method */
1595-
perform_delayable_implementation_check(ce, fn, existing_fn);
1596-
}
1597-
if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1598-
/* Make sure the abstract declaration is compatible with previous declaration */
1599-
perform_delayable_implementation_check(ce, existing_fn, fn);
1600-
return;
1601-
}
1602-
}
1603-
} else {
1604-
ALLOC_HASHTABLE(*overridden);
1605-
zend_hash_init_ex(*overridden, 8, NULL, overridden_ptr_dtor, 0, 0);
1606-
}
1607-
zend_hash_update_mem(*overridden, key, fn, sizeof(zend_function));
1608-
return;
1609-
} else if ((fn->common.fn_flags & ZEND_ACC_ABSTRACT)
1610-
&& !(existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT)) {
1611-
/* Make sure the abstract declaration is compatible with previous declaration */
1612-
perform_delayable_implementation_check(ce, existing_fn, fn);
16131590
return;
16141591
} else if (UNEXPECTED((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)
16151592
&& !(existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT))) {
@@ -1663,7 +1640,7 @@ static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /*
16631640
}
16641641
/* }}} */
16651642

1666-
static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable **overridden, HashTable *exclude_table, zend_class_entry **aliases) /* {{{ */
1643+
static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable *exclude_table, zend_class_entry **aliases) /* {{{ */
16671644
{
16681645
zend_trait_alias *alias, **alias_ptr;
16691646
zend_string *lcname;
@@ -1689,7 +1666,7 @@ static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, z
16891666
}
16901667

16911668
lcname = zend_string_tolower(alias->alias);
1692-
zend_add_trait_method(ce, ZSTR_VAL(alias->alias), lcname, &fn_copy, overridden);
1669+
zend_add_trait_method(ce, ZSTR_VAL(alias->alias), lcname, &fn_copy);
16931670
zend_string_release_ex(lcname, 0);
16941671

16951672
/* Record the trait from which this alias was resolved. */
@@ -1741,7 +1718,7 @@ static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, z
17411718
}
17421719
}
17431720

1744-
zend_add_trait_method(ce, ZSTR_VAL(fn->common.function_name), fnname, &fn_copy, overridden);
1721+
zend_add_trait_method(ce, ZSTR_VAL(fn->common.function_name), fnname, &fn_copy);
17451722
}
17461723
}
17471724
/* }}} */
@@ -1879,7 +1856,6 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e
18791856
static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry **traits, HashTable **exclude_tables, zend_class_entry **aliases) /* {{{ */
18801857
{
18811858
uint32_t i;
1882-
HashTable *overridden = NULL;
18831859
zend_string *key;
18841860
zend_function *fn;
18851861

@@ -1888,7 +1864,7 @@ static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry
18881864
if (traits[i]) {
18891865
/* copies functions, applies defined aliasing, and excludes unused trait methods */
18901866
ZEND_HASH_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
1891-
zend_traits_copy_functions(key, fn, ce, &overridden, exclude_tables[i], aliases);
1867+
zend_traits_copy_functions(key, fn, ce, exclude_tables[i], aliases);
18921868
} ZEND_HASH_FOREACH_END();
18931869

18941870
if (exclude_tables[i]) {
@@ -1902,7 +1878,7 @@ static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry
19021878
for (i = 0; i < ce->num_traits; i++) {
19031879
if (traits[i]) {
19041880
ZEND_HASH_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
1905-
zend_traits_copy_functions(key, fn, ce, &overridden, NULL, aliases);
1881+
zend_traits_copy_functions(key, fn, ce, NULL, aliases);
19061882
} ZEND_HASH_FOREACH_END();
19071883
}
19081884
}
@@ -1911,11 +1887,6 @@ static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry
19111887
ZEND_HASH_FOREACH_PTR(&ce->function_table, fn) {
19121888
zend_fixup_trait_method(fn, ce);
19131889
} ZEND_HASH_FOREACH_END();
1914-
1915-
if (overridden) {
1916-
zend_hash_destroy(overridden);
1917-
FREE_HASHTABLE(overridden);
1918-
}
19191890
}
19201891
/* }}} */
19211892

0 commit comments

Comments
 (0)