Skip to content

Commit 979e609

Browse files
Define Stringable with __toString():string method
1 parent 4cbffd8 commit 979e609

36 files changed

+279
-263
lines changed

Zend/tests/bug26166.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,6 @@ try {
6464
--EXPECT--
6565
Hello World!
6666
===NONE===
67-
Method NoneTest::__toString() must return a string value
67+
Return value of NoneTest::__toString() must be of the type string, none returned
6868
===THROW===
6969
This is an error!

Zend/tests/list_keyed_evaluation_order.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
// Observer objects for the Zend/tests/list_keyed_evaluation_order.* tests
44

5-
class Stringable
5+
class StringCapable
66
{
77
private $name;
88
public function __construct(string $name) {

Zend/tests/list_keyed_evaluation_order.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ list() with keys, evaluation order
55

66
require_once "list_keyed_evaluation_order.inc";
77

8-
$a = new Stringable("A");
9-
$c = new Stringable("C");
8+
$a = new StringCapable("A");
9+
$c = new StringCapable("C");
1010

1111
$e = new IndexableRetrievable("E", new Indexable(["A" => "value for offset A", "C" => "value for offset C"]));
1212

Zend/tests/list_keyed_evaluation_order_nested.phpt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ list() with keys, evaluation order: nested
55

66
require_once "list_keyed_evaluation_order.inc";
77

8-
$a = new Stringable("A");
9-
$c = new Stringable("C");
10-
$f = new Stringable("F");
11-
$g = new Stringable("G");
12-
$i = new Stringable("I");
8+
$a = new StringCapable("A");
9+
$c = new StringCapable("C");
10+
$f = new StringCapable("F");
11+
$g = new StringCapable("G");
12+
$i = new StringCapable("I");
1313

1414
$k = new IndexableRetrievable("K", new Indexable([
1515
"A" => "offset value for A",

Zend/tests/type_declarations/scalar_basic.phpt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ $functions = [
1919
'bool' => function (bool $b) { return $b; }
2020
];
2121

22-
class Stringable {
22+
class StringCapable implements Stringable {
2323
public function __toString() {
2424
return "foobar";
2525
}
@@ -40,7 +40,7 @@ $values = [
4040
NULL,
4141
[],
4242
new StdClass,
43-
new Stringable,
43+
new StringCapable,
4444
fopen("data:text/plain,foobar", "r")
4545
];
4646

@@ -106,7 +106,7 @@ int(0)
106106
}
107107
*** Caught Argument 1 passed to {closure}() must be of the type int, object given, called in %s on line %d
108108

109-
*** Trying object(Stringable)#%s (0) {
109+
*** Trying object(StringCapable)#%s (0) {
110110
}
111111
*** Caught Argument 1 passed to {closure}() must be of the type int, object given, called in %s on line %d
112112

@@ -160,7 +160,7 @@ float(0)
160160
}
161161
*** Caught Argument 1 passed to {closure}() must be of the type float, object given, called in %s on line %d
162162

163-
*** Trying object(Stringable)#%s (0) {
163+
*** Trying object(StringCapable)#%s (0) {
164164
}
165165
*** Caught Argument 1 passed to {closure}() must be of the type float, object given, called in %s on line %d
166166

@@ -213,7 +213,7 @@ string(0) ""
213213
}
214214
*** Caught Argument 1 passed to {closure}() must be of the type string, object given, called in %s on line %d
215215

216-
*** Trying object(Stringable)#%s (0) {
216+
*** Trying object(StringCapable)#%s (0) {
217217
}
218218
string(6) "foobar"
219219

@@ -266,7 +266,7 @@ bool(false)
266266
}
267267
*** Caught Argument 1 passed to {closure}() must be of the type bool, object given, called in %s on line %d
268268

269-
*** Trying object(Stringable)#%s (0) {
269+
*** Trying object(StringCapable)#%s (0) {
270270
}
271271
*** Caught Argument 1 passed to {closure}() must be of the type bool, object given, called in %s on line %d
272272

Zend/tests/type_declarations/scalar_return_basic.phpt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ $functions = [
2121
'bool' => function ($b): bool { return $b; }
2222
];
2323

24-
class Stringable {
24+
class StringCapable {
2525
public function __toString() {
2626
return "foobar";
2727
}
@@ -42,7 +42,7 @@ $values = [
4242
NULL,
4343
[],
4444
new StdClass,
45-
new Stringable,
45+
new StringCapable,
4646
fopen("data:text/plain,foobar", "r")
4747
];
4848

@@ -94,7 +94,7 @@ int(0)
9494
*** Trying object(stdClass)#6 (0) {
9595
}
9696
*** Caught Return value of {closure}() must be of the type int, object returned in %s on line %d
97-
*** Trying object(Stringable)#7 (0) {
97+
*** Trying object(StringCapable)#7 (0) {
9898
}
9999
*** Caught Return value of {closure}() must be of the type int, object returned in %s on line %d
100100
*** Trying resource(5) of type (stream)
@@ -132,7 +132,7 @@ float(0)
132132
*** Trying object(stdClass)#6 (0) {
133133
}
134134
*** Caught Return value of {closure}() must be of the type float, object returned in %s on line %d
135-
*** Trying object(Stringable)#7 (0) {
135+
*** Trying object(StringCapable)#7 (0) {
136136
}
137137
*** Caught Return value of {closure}() must be of the type float, object returned in %s on line %d
138138
*** Trying resource(5) of type (stream)
@@ -169,7 +169,7 @@ string(0) ""
169169
*** Trying object(stdClass)#6 (0) {
170170
}
171171
*** Caught Return value of {closure}() must be of the type string, object returned in %s on line %d
172-
*** Trying object(Stringable)#7 (0) {
172+
*** Trying object(StringCapable)#7 (0) {
173173
}
174174
string(6) "foobar"
175175
*** Trying resource(5) of type (stream)
@@ -206,7 +206,7 @@ bool(false)
206206
*** Trying object(stdClass)#6 (0) {
207207
}
208208
*** Caught Return value of {closure}() must be of the type bool, object returned in %s on line %d
209-
*** Trying object(Stringable)#7 (0) {
209+
*** Trying object(StringCapable)#7 (0) {
210210
}
211211
*** Caught Return value of {closure}() must be of the type bool, object returned in %s on line %d
212212
*** Trying resource(5) of type (stream)

Zend/tests/type_declarations/scalar_return_basic_64bit.phpt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ $functions = [
2121
'bool' => function ($b): bool { return $b; }
2222
];
2323

24-
class Stringable {
24+
class StringCapable {
2525
public function __toString() {
2626
return "foobar";
2727
}
@@ -42,7 +42,7 @@ $values = [
4242
NULL,
4343
[],
4444
new StdClass,
45-
new Stringable,
45+
new StringCapable,
4646
fopen("data:text/plain,foobar", "r")
4747
];
4848

@@ -94,7 +94,7 @@ int(0)
9494
*** Trying object(stdClass)#6 (0) {
9595
}
9696
*** Caught Return value of {closure}() must be of the type int, object returned in %s on line %d
97-
*** Trying object(Stringable)#7 (0) {
97+
*** Trying object(StringCapable)#7 (0) {
9898
}
9999
*** Caught Return value of {closure}() must be of the type int, object returned in %s on line %d
100100
*** Trying resource(5) of type (stream)
@@ -132,7 +132,7 @@ float(0)
132132
*** Trying object(stdClass)#6 (0) {
133133
}
134134
*** Caught Return value of {closure}() must be of the type float, object returned in %s on line %d
135-
*** Trying object(Stringable)#7 (0) {
135+
*** Trying object(StringCapable)#7 (0) {
136136
}
137137
*** Caught Return value of {closure}() must be of the type float, object returned in %s on line %d
138138
*** Trying resource(5) of type (stream)
@@ -169,7 +169,7 @@ string(0) ""
169169
*** Trying object(stdClass)#6 (0) {
170170
}
171171
*** Caught Return value of {closure}() must be of the type string, object returned in %s on line %d
172-
*** Trying object(Stringable)#7 (0) {
172+
*** Trying object(StringCapable)#7 (0) {
173173
}
174174
string(6) "foobar"
175175
*** Trying resource(5) of type (stream)
@@ -206,7 +206,7 @@ bool(false)
206206
*** Trying object(stdClass)#6 (0) {
207207
}
208208
*** Caught Return value of {closure}() must be of the type bool, object returned in %s on line %d
209-
*** Trying object(Stringable)#7 (0) {
209+
*** Trying object(StringCapable)#7 (0) {
210210
}
211211
*** Caught Return value of {closure}() must be of the type bool, object returned in %s on line %d
212212
*** Trying resource(5) of type (stream)

Zend/tests/type_declarations/scalar_strict.phpt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ $functions = [
1313
'bool' => function (bool $b) { return $b; }
1414
];
1515

16-
class Stringable {
16+
class StringCapable {
1717
public function __toString() {
1818
return "foobar";
1919
}
@@ -34,7 +34,7 @@ $values = [
3434
NULL,
3535
[],
3636
new StdClass,
37-
new Stringable,
37+
new StringCapable,
3838
fopen("data:text/plain,foobar", "r")
3939
];
4040

@@ -100,7 +100,7 @@ int(2147483647)
100100
}
101101
*** Caught Argument 1 passed to {closure}() must be of the type int, object given, called in %s on line %d
102102

103-
*** Trying object(Stringable)#6 (0) {
103+
*** Trying object(StringCapable)#6 (0) {
104104
}
105105
*** Caught Argument 1 passed to {closure}() must be of the type int, object given, called in %s on line %d
106106

@@ -153,7 +153,7 @@ float(NAN)
153153
}
154154
*** Caught Argument 1 passed to {closure}() must be of the type float, object given, called in %s on line %d
155155

156-
*** Trying object(Stringable)#6 (0) {
156+
*** Trying object(StringCapable)#6 (0) {
157157
}
158158
*** Caught Argument 1 passed to {closure}() must be of the type float, object given, called in %s on line %d
159159

@@ -206,7 +206,7 @@ string(0) ""
206206
}
207207
*** Caught Argument 1 passed to {closure}() must be of the type string, object given, called in %s on line %d
208208

209-
*** Trying object(Stringable)#6 (0) {
209+
*** Trying object(StringCapable)#6 (0) {
210210
}
211211
*** Caught Argument 1 passed to {closure}() must be of the type string, object given, called in %s on line %d
212212

@@ -259,7 +259,7 @@ bool(false)
259259
}
260260
*** Caught Argument 1 passed to {closure}() must be of the type bool, object given, called in %s on line %d
261261

262-
*** Trying object(Stringable)#6 (0) {
262+
*** Trying object(StringCapable)#6 (0) {
263263
}
264264
*** Caught Argument 1 passed to {closure}() must be of the type bool, object given, called in %s on line %d
265265

Zend/tests/type_declarations/scalar_strict_64bit.phpt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ $functions = [
1313
'bool' => function (bool $b) { return $b; }
1414
];
1515

16-
class Stringable {
16+
class StringCapable {
1717
public function __toString() {
1818
return "foobar";
1919
}
@@ -34,7 +34,7 @@ $values = [
3434
NULL,
3535
[],
3636
new StdClass,
37-
new Stringable,
37+
new StringCapable,
3838
fopen("data:text/plain,foobar", "r")
3939
];
4040

@@ -100,7 +100,7 @@ int(9223372036854775807)
100100
}
101101
*** Caught Argument 1 passed to {closure}() must be of the type int, object given, called in %s on line %d
102102

103-
*** Trying object(Stringable)#6 (0) {
103+
*** Trying object(StringCapable)#6 (0) {
104104
}
105105
*** Caught Argument 1 passed to {closure}() must be of the type int, object given, called in %s on line %d
106106

@@ -153,7 +153,7 @@ float(NAN)
153153
}
154154
*** Caught Argument 1 passed to {closure}() must be of the type float, object given, called in %s on line %d
155155

156-
*** Trying object(Stringable)#6 (0) {
156+
*** Trying object(StringCapable)#6 (0) {
157157
}
158158
*** Caught Argument 1 passed to {closure}() must be of the type float, object given, called in %s on line %d
159159

@@ -206,7 +206,7 @@ string(0) ""
206206
}
207207
*** Caught Argument 1 passed to {closure}() must be of the type string, object given, called in %s on line %d
208208

209-
*** Trying object(Stringable)#6 (0) {
209+
*** Trying object(StringCapable)#6 (0) {
210210
}
211211
*** Caught Argument 1 passed to {closure}() must be of the type string, object given, called in %s on line %d
212212

@@ -259,7 +259,7 @@ bool(false)
259259
}
260260
*** Caught Argument 1 passed to {closure}() must be of the type bool, object given, called in %s on line %d
261261

262-
*** Trying object(Stringable)#6 (0) {
262+
*** Trying object(StringCapable)#6 (0) {
263263
}
264264
*** Caught Argument 1 passed to {closure}() must be of the type bool, object given, called in %s on line %d
265265

Zend/zend_compile.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5673,21 +5673,25 @@ static zend_bool zend_is_valid_default_value(zend_type type, zval *value)
56735673
return 0;
56745674
}
56755675

5676-
void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */
5676+
void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32_t fallback_return_type) /* {{{ */
56775677
{
56785678
zend_ast_list *list = zend_ast_get_list(ast);
56795679
uint32_t i;
56805680
zend_op_array *op_array = CG(active_op_array);
56815681
zend_arg_info *arg_infos;
56825682

5683-
if (return_type_ast) {
5683+
if (return_type_ast || fallback_return_type) {
56845684
/* Use op_array->arg_info[-1] for return type */
56855685
arg_infos = safe_emalloc(sizeof(zend_arg_info), list->children + 1, 0);
56865686
arg_infos->name = NULL;
5687-
arg_infos->type = zend_compile_typename(
5688-
return_type_ast, /* force_allow_null */ 0, /* use_arena */ 0);
5689-
ZEND_TYPE_FULL_MASK(arg_infos->type) |= _ZEND_ARG_INFO_FLAGS(
5690-
(op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0, /* is_variadic */ 0);
5687+
if (return_type_ast) {
5688+
arg_infos->type = zend_compile_typename(
5689+
return_type_ast, /* force_allow_null */ 0, /* use_arena */ 0);
5690+
ZEND_TYPE_FULL_MASK(arg_infos->type) |= _ZEND_ARG_INFO_FLAGS(
5691+
(op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0, /* is_variadic */ 0);
5692+
} else {
5693+
arg_infos->type = (zend_type) ZEND_TYPE_INIT_CODE(fallback_return_type, 0, 0);
5694+
}
56915695
arg_infos++;
56925696
op_array->fn_flags |= ZEND_ACC_HAS_RETURN_TYPE;
56935697
} else {
@@ -6238,7 +6242,7 @@ void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /*
62386242
zend_stack_push(&CG(loop_var_stack), (void *) &dummy_var);
62396243
}
62406244

6241-
zend_compile_params(params_ast, return_type_ast);
6245+
zend_compile_params(params_ast, return_type_ast, is_method && zend_string_equals_ci(decl->name, "__toString") ? IS_STRING : 0);
62426246
if (CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) {
62436247
zend_mark_function_as_generator();
62446248
zend_emit_op(NULL, ZEND_GENERATOR_CREATE, NULL, NULL);

Zend/zend_exceptions.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,6 @@ static const zend_function_entry zend_funcs_throwable[] = {
763763
ZEND_ABSTRACT_ME(throwable, getTrace, arginfo_class_Throwable_getTrace)
764764
ZEND_ABSTRACT_ME(throwable, getPrevious, arginfo_class_Throwable_getPrevious)
765765
ZEND_ABSTRACT_ME(throwable, getTraceAsString, arginfo_class_Throwable_getTraceAsString)
766-
ZEND_ABSTRACT_ME(throwable, __toString, arginfo_class_Throwable___toString)
767766
ZEND_FE_END
768767
};
769768
/* }}} */
@@ -805,6 +804,7 @@ void zend_register_default_exception(void) /* {{{ */
805804
zend_class_entry ce;
806805

807806
REGISTER_MAGIC_INTERFACE(throwable, Throwable);
807+
zend_class_implements(zend_ce_throwable, 1, zend_ce_stringable);
808808

809809
memcpy(&default_exception_handlers, &std_object_handlers, sizeof(zend_object_handlers));
810810
default_exception_handlers.clone_obj = NULL;

Zend/zend_exceptions.stub.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
interface Throwable
3+
interface Throwable extends Stringable
44
{
55
/** @return string */
66
function getMessage();
@@ -22,9 +22,6 @@ function getPrevious();
2222

2323
/** @return string */
2424
function getTraceAsString();
25-
26-
/** @return string */
27-
function __toString();
2825
}
2926

3027
class Exception implements Throwable
@@ -56,8 +53,7 @@ final function getPrevious() {}
5653
/** @return string */
5754
final function getTraceAsString() {}
5855

59-
/** @return string */
60-
function __toString() {}
56+
function __toString(): string {}
6157
}
6258

6359
class ErrorException extends Exception

0 commit comments

Comments
 (0)