Skip to content

Commit 80e90ad

Browse files
committed
Add number or str ZPP macros
1 parent 53829b7 commit 80e90ad

File tree

6 files changed

+194
-1
lines changed

6 files changed

+194
-1
lines changed

Zend/tests/number_or_str_zpp.phpt

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
--TEST--
2+
Test Z_PARAM_NUMBER_OR_STR() and Z_PARAM_NUMBER_OR_STR_OR_NULL
3+
--EXTENSIONS--
4+
zend_test
5+
--FILE--
6+
<?php
7+
8+
class Foo {}
9+
class ToString {
10+
public function __toString() {
11+
return "ToString";
12+
}
13+
}
14+
15+
var_dump(zend_number_or_string("string"));
16+
var_dump(zend_number_or_string(1));
17+
var_dump(zend_number_or_string(5.5));
18+
var_dump(zend_number_or_string(null));
19+
var_dump(zend_number_or_string(false));
20+
var_dump(zend_number_or_string(true));
21+
var_dump(zend_number_or_string(new ToString()));
22+
23+
try {
24+
zend_string_or_object([]);
25+
} catch (TypeError $exception) {
26+
echo $exception->getMessage() . "\n";
27+
}
28+
try {
29+
zend_number_or_string(new Foo());
30+
} catch (TypeError $exception) {
31+
echo $exception->getMessage() . "\n";
32+
}
33+
34+
var_dump(zend_number_or_string_or_null("string"));
35+
var_dump(zend_number_or_string_or_null(1));
36+
var_dump(zend_number_or_string_or_null(5.5));
37+
var_dump(zend_number_or_string_or_null(null));
38+
var_dump(zend_number_or_string_or_null(false));
39+
var_dump(zend_number_or_string_or_null(true));
40+
var_dump(zend_number_or_string_or_null(new ToString()));
41+
42+
try {
43+
zend_number_or_string_or_null([]);
44+
} catch (TypeError $exception) {
45+
echo $exception->getMessage() . "\n";
46+
}
47+
try {
48+
zend_number_or_string_or_null(new Foo());
49+
} catch (TypeError $exception) {
50+
echo $exception->getMessage() . "\n";
51+
}
52+
53+
?>
54+
--EXPECTF--
55+
string(6) "string"
56+
int(1)
57+
float(5.5)
58+
59+
Deprecated: zend_number_or_string(): Passing null to parameter #1 ($param) of type string|int|float is deprecated in %s on line %d
60+
int(0)
61+
int(0)
62+
int(1)
63+
string(8) "ToString"
64+
zend_string_or_object(): Argument #1 ($param) must be of type object|string, array given
65+
zend_number_or_string(): Argument #1 ($param) must be of type string|int|float, Foo given
66+
string(6) "string"
67+
int(1)
68+
float(5.5)
69+
NULL
70+
int(0)
71+
int(1)
72+
string(8) "ToString"
73+
zend_number_or_string_or_null(): Argument #1 ($param) must be of type string|int|float|null, array given
74+
zend_number_or_string_or_null(): Argument #1 ($param) must be of type string|int|float|null, Foo given

Zend/zend_API.c

+30
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,36 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_number_slow(zval *arg, zval **dest, u
674674
}
675675
/* }}} */
676676

677+
678+
ZEND_API bool ZEND_FASTCALL zend_parse_arg_number_or_str_slow(zval *arg, zval **dest, uint32_t arg_num) /* {{{ */
679+
{
680+
if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
681+
return false;
682+
}
683+
if (Z_TYPE_P(arg) < IS_TRUE) {
684+
if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("string|int|float", arg_num)) {
685+
return false;
686+
}
687+
ZVAL_LONG(arg, 0);
688+
} else if (Z_TYPE_P(arg) == IS_TRUE) {
689+
ZVAL_LONG(arg, 1);
690+
} else if (UNEXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) {
691+
zend_object *zobj = Z_OBJ_P(arg);
692+
zval obj;
693+
if (zobj->handlers->cast_object(zobj, &obj, IS_STRING) == SUCCESS) {
694+
OBJ_RELEASE(zobj);
695+
ZVAL_COPY_VALUE(arg, &obj);
696+
*dest = arg;
697+
return true;
698+
}
699+
return false;
700+
} else {
701+
return false;
702+
}
703+
*dest = arg;
704+
return true;
705+
}
706+
677707
ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_weak(zval *arg, zend_string **dest, uint32_t arg_num) /* {{{ */
678708
{
679709
if (EXPECTED(Z_TYPE_P(arg) < IS_STRING)) {

Zend/zend_API.h

+29
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,8 @@ static zend_always_inline zval *zend_try_array_init(zval *zv)
15201520
_(Z_EXPECTED_DOUBLE_OR_NULL, "of type ?float") \
15211521
_(Z_EXPECTED_NUMBER, "of type int|float") \
15221522
_(Z_EXPECTED_NUMBER_OR_NULL, "of type int|float|null") \
1523+
_(Z_EXPECTED_NUMBER_OR_STRING, "of type string|int|float") \
1524+
_(Z_EXPECTED_NUMBER_OR_STRING_OR_NULL, "of type string|int|float|null") \
15231525
_(Z_EXPECTED_ARRAY_OR_STRING, "of type array|string") \
15241526
_(Z_EXPECTED_ARRAY_OR_STRING_OR_NULL, "of type array|string|null") \
15251527
_(Z_EXPECTED_STRING_OR_LONG, "of type string|int") \
@@ -1891,6 +1893,20 @@ ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *
18911893
#define Z_PARAM_NUMBER(dest) \
18921894
Z_PARAM_NUMBER_EX(dest, 0)
18931895

1896+
#define Z_PARAM_NUMBER_OR_STR_EX(dest, check_null) \
1897+
Z_PARAM_PROLOGUE(0, 0); \
1898+
if (UNEXPECTED(!zend_parse_arg_number_or_str(_arg, &dest, check_null, _i))) { \
1899+
_expected_type = check_null ? Z_EXPECTED_NUMBER_OR_STRING_OR_NULL : Z_EXPECTED_NUMBER_OR_STRING; \
1900+
_error_code = ZPP_ERROR_WRONG_ARG; \
1901+
break; \
1902+
}
1903+
1904+
#define Z_PARAM_NUMBER_OR_STR(dest) \
1905+
Z_PARAM_NUMBER_OR_STR_EX(dest, false)
1906+
1907+
#define Z_PARAM_NUMBER_OR_STR_OR_NULL(dest) \
1908+
Z_PARAM_NUMBER_OR_STR_EX(dest, true)
1909+
18941910
/* old "o" */
18951911
#define Z_PARAM_OBJECT_EX(dest, check_null, deref) \
18961912
Z_PARAM_PROLOGUE(deref, 0); \
@@ -2145,6 +2161,7 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_weak(const zval *arg, double *
21452161
ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_slow(zval *arg, zend_string **dest, uint32_t arg_num);
21462162
ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_weak(zval *arg, zend_string **dest, uint32_t arg_num);
21472163
ZEND_API bool ZEND_FASTCALL zend_parse_arg_number_slow(zval *arg, zval **dest, uint32_t arg_num);
2164+
ZEND_API bool ZEND_FASTCALL zend_parse_arg_number_or_str_slow(zval *arg, zval **dest, uint32_t arg_num);
21482165
ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_or_long_slow(zval *arg, zend_string **dest_str, zend_long *dest_long, uint32_t arg_num);
21492166

21502167
static zend_always_inline bool zend_parse_arg_bool(const zval *arg, bool *dest, bool *is_null, bool check_null, uint32_t arg_num)
@@ -2209,6 +2226,18 @@ static zend_always_inline bool zend_parse_arg_number(zval *arg, zval **dest, boo
22092226
return 1;
22102227
}
22112228

2229+
static zend_always_inline bool zend_parse_arg_number_or_str(zval *arg, zval **dest, bool check_null, uint32_t arg_num)
2230+
{
2231+
if (EXPECTED(Z_TYPE_P(arg) == IS_LONG || Z_TYPE_P(arg) == IS_DOUBLE || Z_TYPE_P(arg) == IS_STRING)) {
2232+
*dest = arg;
2233+
} else if (check_null && EXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
2234+
*dest = NULL;
2235+
} else {
2236+
return zend_parse_arg_number_or_str_slow(arg, dest, arg_num);
2237+
}
2238+
return true;
2239+
}
2240+
22122241
static zend_always_inline bool zend_parse_arg_str(zval *arg, zend_string **dest, bool check_null, uint32_t arg_num)
22132242
{
22142243
if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) {

ext/zend_test/test.c

+44
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,50 @@ static ZEND_FUNCTION(zend_string_or_stdclass_or_null)
266266
}
267267
}
268268

269+
/* Tests Z_PARAM_NUMBER_OR_STR */
270+
static ZEND_FUNCTION(zend_number_or_string)
271+
{
272+
zval *input;
273+
274+
ZEND_PARSE_PARAMETERS_START(1, 1)
275+
Z_PARAM_NUMBER_OR_STR(input)
276+
ZEND_PARSE_PARAMETERS_END();
277+
278+
switch (Z_TYPE_P(input)) {
279+
case IS_LONG:
280+
RETURN_LONG(Z_LVAL_P(input));
281+
case IS_DOUBLE:
282+
RETURN_DOUBLE(Z_DVAL_P(input));
283+
case IS_STRING:
284+
RETURN_STR_COPY(Z_STR_P(input));
285+
EMPTY_SWITCH_DEFAULT_CASE();
286+
}
287+
}
288+
289+
/* Tests Z_PARAM_NUMBER_OR_STR_OR_NULL */
290+
static ZEND_FUNCTION(zend_number_or_string_or_null)
291+
{
292+
zval *input;
293+
294+
ZEND_PARSE_PARAMETERS_START(1, 1)
295+
Z_PARAM_NUMBER_OR_STR_OR_NULL(input)
296+
ZEND_PARSE_PARAMETERS_END();
297+
298+
if (!input) {
299+
RETURN_NULL();
300+
}
301+
302+
switch (Z_TYPE_P(input)) {
303+
case IS_LONG:
304+
RETURN_LONG(Z_LVAL_P(input));
305+
case IS_DOUBLE:
306+
RETURN_DOUBLE(Z_DVAL_P(input));
307+
case IS_STRING:
308+
RETURN_STR_COPY(Z_STR_P(input));
309+
EMPTY_SWITCH_DEFAULT_CASE();
310+
}
311+
}
312+
269313
static ZEND_FUNCTION(zend_weakmap_attach)
270314
{
271315
zval *value;

ext/zend_test/test.stub.php

+4
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ function zend_string_or_stdclass($param): stdClass|string {}
162162
/** @param stdClass|string|null $param */
163163
function zend_string_or_stdclass_or_null($param): stdClass|string|null {}
164164

165+
function zend_number_or_string(string|int|float $param): string|int|float {}
166+
167+
function zend_number_or_string_or_null(string|int|float|null $param): string|int|float|null {}
168+
165169
function zend_iterable(iterable $arg1, ?iterable $arg2 = null): void {}
166170

167171
function zend_weakmap_attach(object $object, mixed $value): bool {}

ext/zend_test/test_arginfo.h

+13-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)