Skip to content

Commit d478ae7

Browse files
committed
Don't implement Stringable on traits
Traits do not support interfaces, so we should not implement Stringable on them. Also check the __toString() return type in the same way other magic methods do, otherwise we would now miss the check in the trait case.
1 parent 7e67366 commit d478ae7

File tree

6 files changed

+25
-10
lines changed

6 files changed

+25
-10
lines changed

Zend/tests/return_types/036.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ class Foo {
88
}
99
?>
1010
--EXPECTF--
11-
Fatal error: Declaration of Foo::__toString(): bool must be compatible with Stringable::__toString(): string in %s on line %d
11+
Fatal error: Foo::__toString(): Return type must be string when declared in %s on line %d

Zend/tests/stringable_trait.phpt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,31 @@ trait T {
88
return "ok";
99
}
1010
}
11+
trait T2 {
12+
use T;
13+
}
1114

1215
class C {
1316
use T;
1417
}
18+
class C2 {
19+
use T2;
20+
}
1521

1622
var_dump(new C instanceof Stringable);
23+
var_dump(new C2 instanceof Stringable);
24+
25+
// The traits themselves should not implement Stringable -- traits cannot implement interfaces.
26+
$rc = new ReflectionClass(T::class);
27+
var_dump($rc->getInterfaceNames());
28+
$rc = new ReflectionClass(T2::class);
29+
var_dump($rc->getInterfaceNames());
1730

1831
?>
1932
--EXPECT--
2033
bool(true)
34+
bool(true)
35+
array(0) {
36+
}
37+
array(0) {
38+
}

Zend/tests/stringable_trait_invalid.phpt

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,6 @@ trait T {
99
}
1010
}
1111

12-
class C {
13-
use T;
14-
}
15-
16-
var_dump(new C instanceof Stringable);
17-
1812
?>
1913
--EXPECTF--
20-
Fatal error: Declaration of T::__toString(): int must be compatible with Stringable::__toString(): string in %s on line %d
14+
Fatal error: T::__toString(): Return type must be string when declared in %s on line %d

Zend/zend_API.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2233,6 +2233,7 @@ ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce,
22332233
zend_check_magic_method_args(0, ce, fptr, error_type);
22342234
zend_check_magic_method_non_static(ce, fptr, error_type);
22352235
zend_check_magic_method_public(ce, fptr, error_type);
2236+
zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_STRING);
22362237
} else if (zend_string_equals_literal(lcname, ZEND_DEBUGINFO_FUNC_NAME)) {
22372238
zend_check_magic_method_args(0, ce, fptr, error_type);
22382239
zend_check_magic_method_non_static(ce, fptr, error_type);

Zend/zend_compile.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6817,7 +6817,8 @@ zend_string *zend_begin_method_decl(zend_op_array *op_array, zend_string *name,
68176817
}
68186818

68196819
zend_add_magic_method(ce, (zend_function *) op_array, lcname);
6820-
if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME)) {
6820+
if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME)
6821+
&& !(ce->ce_flags & ZEND_ACC_TRAIT)) {
68216822
add_stringable_interface(ce);
68226823
}
68236824

Zend/zend_inheritance.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2487,7 +2487,8 @@ ZEND_API zend_result zend_do_link_class(zend_class_entry *ce, zend_string *lc_pa
24872487

24882488
/* Normally Stringable is added during compilation. However, if it is imported from a trait,
24892489
* we need to explicilty add the interface here. */
2490-
if (ce->__tostring && !zend_class_implements_interface(ce, zend_ce_stringable)) {
2490+
if (ce->__tostring && !(ce->ce_flags & ZEND_ACC_TRAIT)
2491+
&& !zend_class_implements_interface(ce, zend_ce_stringable)) {
24912492
ZEND_ASSERT(ce->__tostring->common.fn_flags & ZEND_ACC_TRAIT_CLONE);
24922493
ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
24932494
ce->num_interfaces++;

0 commit comments

Comments
 (0)