diff --git a/Zend/tests/inheritance/gh23630.phpt b/Zend/tests/inheritance/gh23630.phpt new file mode 100644 index 000000000000..713506c6136b --- /dev/null +++ b/Zend/tests/inheritance/gh23630.phpt @@ -0,0 +1,40 @@ +--TEST-- +GH-23630: Interface inheritance depends on the order of the parent interfaces +--FILE-- +getDeclaringClass()->getName(), $method->getNumberOfParameters()); +} + +?> +--EXPECT-- +string(1) "B" +int(2) +string(1) "B" +int(2) +string(1) "B" +int(2) +string(1) "B" +int(2) diff --git a/Zend/tests/inheritance/gh23630_2.phpt b/Zend/tests/inheritance/gh23630_2.phpt new file mode 100644 index 000000000000..5b47ac7d1a8a --- /dev/null +++ b/Zend/tests/inheritance/gh23630_2.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-23630: Implementation must satisfy the most specific parent interface +--FILE-- + +--EXPECTF-- +Fatal error: Declaration of Test::__construct(?string $name = null) must be compatible with B::__construct(?string $name = null, ?int $id = null) in %s on line %d diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 4424c9a1a3ab..b060eb868bdb 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -1241,6 +1241,16 @@ static inheritance_status do_inheritance_check_on_method( } /* }}} */ +static inheritance_status check_interface_method_compatibility( + zend_function *child, zend_function *parent, zend_class_entry *ce) /* {{{ */ +{ + return do_inheritance_check_on_method( + child, child->common.scope, parent, parent->common.scope, ce, NULL, + ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY + | ZEND_INHERITANCE_CHECK_SILENT); +} +/* }}} */ + static void do_inherit_method(zend_string *key, zend_function *parent, zend_class_entry *ce, bool is_interface, uint32_t flags) /* {{{ */ { zval *child = zend_hash_find_known_hash(&ce->function_table, key); @@ -1253,6 +1263,16 @@ static void do_inherit_method(zend_string *key, zend_function *parent, zend_clas return; } + /* Otherwise linking would depend on the order the interfaces are listed in */ + if (is_interface + && func->common.scope != ce + && (func->common.scope->ce_flags & ZEND_ACC_INTERFACE) + && check_interface_method_compatibility(func, parent, ce) == INHERITANCE_ERROR + && check_interface_method_compatibility(parent, func, ce) == INHERITANCE_SUCCESS) { + zend_hash_update_ptr(&ce->function_table, key, zend_duplicate_function(parent, ce)); + return; + } + do_inheritance_check_on_method( func, func->common.scope, parent, parent->common.scope, ce, child, flags); } else {