Skip to content

Commit d23f69a

Browse files
committed
Check abstract method signatures coming from traits
1 parent d4de3f9 commit d23f69a

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);
@@ -1552,7 +1546,7 @@ static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zen
15521546
}
15531547
/* }}} */
15541548

1555-
static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_string *key, zend_function *fn, HashTable **overridden) /* {{{ */
1549+
static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_string *key, zend_function *fn) /* {{{ */
15561550
{
15571551
zend_function *existing_fn = NULL;
15581552
zend_function *new_fn;
@@ -1566,31 +1560,14 @@ static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_s
15661560
return;
15671561
}
15681562

1563+
/* Abstract method signatures from the trait must be satisfied. */
1564+
if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1565+
perform_delayable_implementation_check(ce, existing_fn, fn);
1566+
return;
1567+
}
1568+
15691569
if (existing_fn->common.scope == ce) {
15701570
/* members from the current class override trait methods */
1571-
/* use temporary *overridden HashTable to detect hidden conflict */
1572-
if (*overridden) {
1573-
if ((existing_fn = zend_hash_find_ptr(*overridden, key)) != NULL) {
1574-
if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1575-
/* Make sure the trait method is compatible with previosly declared abstract method */
1576-
perform_delayable_implementation_check(ce, fn, existing_fn);
1577-
}
1578-
if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1579-
/* Make sure the abstract declaration is compatible with previous declaration */
1580-
perform_delayable_implementation_check(ce, existing_fn, fn);
1581-
return;
1582-
}
1583-
}
1584-
} else {
1585-
ALLOC_HASHTABLE(*overridden);
1586-
zend_hash_init_ex(*overridden, 8, NULL, overridden_ptr_dtor, 0, 0);
1587-
}
1588-
zend_hash_update_mem(*overridden, key, fn, sizeof(zend_function));
1589-
return;
1590-
} else if ((fn->common.fn_flags & ZEND_ACC_ABSTRACT)
1591-
&& !(existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT)) {
1592-
/* Make sure the abstract declaration is compatible with previous declaration */
1593-
perform_delayable_implementation_check(ce, existing_fn, fn);
15941571
return;
15951572
} else if (UNEXPECTED((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)
15961573
&& !(existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT))) {
@@ -1644,7 +1621,7 @@ static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /*
16441621
}
16451622
/* }}} */
16461623

1647-
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) /* {{{ */
1624+
static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable *exclude_table, zend_class_entry **aliases) /* {{{ */
16481625
{
16491626
zend_trait_alias *alias, **alias_ptr;
16501627
zend_string *lcname;
@@ -1670,7 +1647,7 @@ static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, z
16701647
}
16711648

16721649
lcname = zend_string_tolower(alias->alias);
1673-
zend_add_trait_method(ce, ZSTR_VAL(alias->alias), lcname, &fn_copy, overridden);
1650+
zend_add_trait_method(ce, ZSTR_VAL(alias->alias), lcname, &fn_copy);
16741651
zend_string_release_ex(lcname, 0);
16751652

16761653
/* Record the trait from which this alias was resolved. */
@@ -1722,7 +1699,7 @@ static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, z
17221699
}
17231700
}
17241701

1725-
zend_add_trait_method(ce, ZSTR_VAL(fn->common.function_name), fnname, &fn_copy, overridden);
1702+
zend_add_trait_method(ce, ZSTR_VAL(fn->common.function_name), fnname, &fn_copy);
17261703
}
17271704
}
17281705
/* }}} */
@@ -1860,7 +1837,6 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e
18601837
static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry **traits, HashTable **exclude_tables, zend_class_entry **aliases) /* {{{ */
18611838
{
18621839
uint32_t i;
1863-
HashTable *overridden = NULL;
18641840
zend_string *key;
18651841
zend_function *fn;
18661842

@@ -1869,7 +1845,7 @@ static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry
18691845
if (traits[i]) {
18701846
/* copies functions, applies defined aliasing, and excludes unused trait methods */
18711847
ZEND_HASH_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
1872-
zend_traits_copy_functions(key, fn, ce, &overridden, exclude_tables[i], aliases);
1848+
zend_traits_copy_functions(key, fn, ce, exclude_tables[i], aliases);
18731849
} ZEND_HASH_FOREACH_END();
18741850

18751851
if (exclude_tables[i]) {
@@ -1883,7 +1859,7 @@ static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry
18831859
for (i = 0; i < ce->num_traits; i++) {
18841860
if (traits[i]) {
18851861
ZEND_HASH_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
1886-
zend_traits_copy_functions(key, fn, ce, &overridden, NULL, aliases);
1862+
zend_traits_copy_functions(key, fn, ce, NULL, aliases);
18871863
} ZEND_HASH_FOREACH_END();
18881864
}
18891865
}
@@ -1892,11 +1868,6 @@ static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry
18921868
ZEND_HASH_FOREACH_PTR(&ce->function_table, fn) {
18931869
zend_fixup_trait_method(fn, ce);
18941870
} ZEND_HASH_FOREACH_END();
1895-
1896-
if (overridden) {
1897-
zend_hash_destroy(overridden);
1898-
FREE_HASHTABLE(overridden);
1899-
}
19001871
}
19011872
/* }}} */
19021873

0 commit comments

Comments
 (0)