Skip to content

Commit 9d0c60d

Browse files
committed
Fix prototype for trait methods
Fixes GH-14009
1 parent b3e26c3 commit 9d0c60d

File tree

4 files changed

+99
-15
lines changed

4 files changed

+99
-15
lines changed

Zend/tests/gh14009.phpt

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
GH-14009: Traits inherit prototype
3+
--FILE--
4+
<?php
5+
6+
class P {
7+
protected function common() {
8+
throw new Exception('Unreachable');
9+
}
10+
}
11+
12+
class A extends P {
13+
public function test(P $sibling) {
14+
$sibling->common();
15+
}
16+
}
17+
18+
class B extends P {
19+
protected function common() {
20+
echo __METHOD__, "\n";
21+
}
22+
}
23+
24+
trait T {
25+
protected function common() {
26+
echo __METHOD__, "\n";
27+
}
28+
}
29+
30+
class C extends P {
31+
use T;
32+
}
33+
34+
$a = new A();
35+
$a->test(new B());
36+
$a->test(new C());
37+
38+
?>
39+
--EXPECT--
40+
B::common
41+
T::common
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
Interfaces don't set prototypes to their parent method
3+
--FILE--
4+
<?php
5+
6+
interface A {
7+
public function __construct(int $param);
8+
}
9+
interface B extends A {
10+
public function __construct(int|float $param);
11+
}
12+
class Test implements B {
13+
public function __construct(int $param) {}
14+
}
15+
new Test(42);
16+
17+
?>
18+
--EXPECTF--
19+
Fatal error: Declaration of Test::__construct(int $param) must be compatible with B::__construct(int|float $param) in %s on line %d
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--TEST--
2+
Interfaces don't set prototypes to their parent method
3+
--XFAIL--
4+
X::__constructor()'s prototype is set to B::__construct(). Y::__construct() then
5+
uses prototype to verify LSP, but misses A::__construct() which has a stricter
6+
signature.
7+
--FILE--
8+
<?php
9+
10+
interface A {
11+
public function __construct(int|float $param);
12+
}
13+
interface B {
14+
public function __construct(int $param);
15+
}
16+
class X implements A, B {
17+
public function __construct(int|float $param) {}
18+
}
19+
class Y extends X {
20+
public function __construct(int $param) {}
21+
}
22+
new Y(42);
23+
24+
?>
25+
--EXPECT--
26+
Fatal error: Declaration of Y::__construct(int $param) must be compatible with A::__construct(int|float $param) in %s on line %d

Zend/zend_inheritance.c

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,21 +1146,19 @@ static zend_always_inline inheritance_status do_inheritance_check_on_method_ex(
11461146
parent = proto;
11471147
}
11481148

1149-
if (!check_only && child->common.prototype != proto && child_zv) {
1150-
do {
1151-
if (child->common.scope != ce && child->type == ZEND_USER_FUNCTION) {
1152-
if (ce->ce_flags & ZEND_ACC_INTERFACE) {
1153-
/* Few parent interfaces contain the same method */
1154-
break;
1155-
} else {
1156-
/* op_array wasn't duplicated yet */
1157-
zend_function *new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
1158-
memcpy(new_function, child, sizeof(zend_op_array));
1159-
Z_PTR_P(child_zv) = child = new_function;
1160-
}
1161-
}
1162-
child->common.prototype = proto;
1163-
} while (0);
1149+
if (!check_only && child->common.prototype != proto
1150+
&& (child_scope == ce || child_zv)
1151+
/* We are not setting the prototype of overridden interface methods because of abstract constructors.
1152+
* See Zend/tests/interface_constructor_prototype_001.phpt. */
1153+
&& !(ce->ce_flags & ZEND_ACC_INTERFACE)) {
1154+
if (child_scope != ce && child->type == ZEND_USER_FUNCTION) {
1155+
/* op_array wasn't duplicated yet */
1156+
ZEND_ASSERT(child_zv);
1157+
zend_function *new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
1158+
memcpy(new_function, child, sizeof(zend_op_array));
1159+
Z_PTR_P(child_zv) = child = new_function;
1160+
}
1161+
child->common.prototype = proto;
11641162
}
11651163

11661164
/* Prevent derived classes from restricting access that was available in parent classes (except deriving from non-abstract ctors) */

0 commit comments

Comments
 (0)