Skip to content

Commit 422b0c8

Browse files
committed
Improve TypeError messages for non-numeric/empty strings in coercions
Implements proposal from #20632
1 parent 114260b commit 422b0c8

File tree

5 files changed

+62
-1
lines changed

5 files changed

+62
-1
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
Error message for non-numaric strings in arithmetic contexts
3+
--FILE--
4+
<?php
5+
declare(strict_types=0);
6+
7+
function foo(int $a) { echo $a; }
8+
9+
function msg(TypeError $e){
10+
$split = explode(', called in', $e->getMessage(), 2);
11+
return $split[0];
12+
}
13+
14+
var_dump(1 + "1");
15+
try { var_dump(1 + "hello"); } catch (TypeError $e) { echo $e->getMessage(), "\n"; }
16+
try { var_dump(1 + ""); } catch (TypeError $e) { echo $e->getMessage(), "\n"; }
17+
try { var_dump("hello" + 1); } catch (TypeError $e) { echo $e->getMessage(), "\n"; }
18+
try { var_dump("" + 1); } catch (TypeError $e) { echo $e->getMessage(), "\n"; }
19+
20+
foo("1");
21+
echo "\n";
22+
try { foo("hello"); } catch (TypeError $e) { echo msg($e), "\n"; }
23+
try { foo(""); } catch (TypeError $e) { echo msg($e), "\n"; }
24+
?>
25+
===DONE===
26+
--EXPECT--
27+
int(2)
28+
Unsupported operand types: int + non-numeric string
29+
Unsupported operand types: int + empty string
30+
Unsupported operand types: non-numeric string + int
31+
Unsupported operand types: empty string + int
32+
1
33+
foo(): Argument #1 ($a) must be of type int, non-numeric string given
34+
foo(): Argument #1 ($a) must be of type int, empty string given
35+
===DONE===

Zend/zend_API.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,26 @@ ZEND_API const char *zend_zval_value_name(const zval *arg)
149149
return zend_get_type_by_const(Z_TYPE_P(arg));
150150
}
151151

152+
ZEND_API const char *zend_zval_namaric_string_value_name(const zval *arg)
153+
{
154+
const zval *val = arg;
155+
156+
if (Z_TYPE_P(val) == IS_REFERENCE) {
157+
val = Z_REFVAL_P(val);
158+
}
159+
160+
if (Z_TYPE_P(val) == IS_STRING) {
161+
if (Z_STRLEN_P(val) == 0) {
162+
return "empty string";
163+
}
164+
165+
return "non-numeric string";
166+
}
167+
168+
return zend_zval_type_name(val);
169+
}
170+
171+
152172
ZEND_API const char *zend_zval_type_name(const zval *arg)
153173
{
154174
ZVAL_DEREF(arg);
@@ -164,6 +184,8 @@ ZEND_API const char *zend_zval_type_name(const zval *arg)
164184
return zend_get_type_by_const(Z_TYPE_P(arg));
165185
}
166186

187+
188+
167189
/* This API exists *only* for use in gettype().
168190
* For anything else, you likely want zend_zval_type_name(). */
169191
ZEND_API zend_string *zend_zval_get_legacy_type(const zval *arg) /* {{{ */

Zend/zend_API.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ ZEND_API zend_result zend_parse_parameters_ex(int flags, uint32_t num_args, cons
365365
zend_parse_parameters(num_args, __VA_ARGS__)
366366
ZEND_API const char *zend_zval_type_name(const zval *arg);
367367
ZEND_API const char *zend_zval_value_name(const zval *arg);
368+
ZEND_API const char *zend_zval_namaric_string_value_name(const zval *arg);
368369
ZEND_API zend_string *zend_zval_get_legacy_type(const zval *arg);
369370

370371
ZEND_API zend_result zend_parse_method_parameters(uint32_t num_args, zval *this_ptr, const char *type_spec, ...);

Zend/zend_execute.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,9 @@ ZEND_API ZEND_COLD void zend_verify_arg_error(
718718

719719
ZEND_ASSERT(zf->common.type == ZEND_USER_FUNCTION
720720
&& "Arginfo verification is not performed for internal functions");
721+
722+
given_msg = zend_zval_namaric_string_value_name(value);
723+
721724
if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) {
722725
zend_argument_type_error(arg_num, "must be of type %s, %s given, called in %s on line %d",
723726
ZSTR_VAL(need_msg), given_msg,

Zend/zend_operators.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1122,7 +1122,7 @@ static ZEND_COLD zend_never_inline void ZEND_FASTCALL zend_binop_error(const cha
11221122
}
11231123

11241124
zend_type_error("Unsupported operand types: %s %s %s",
1125-
zend_zval_type_name(op1), operator, zend_zval_type_name(op2));
1125+
zend_zval_namaric_string_value_name(op1), operator, zend_zval_namaric_string_value_name(op2));
11261126
}
11271127
/* }}} */
11281128

0 commit comments

Comments
 (0)