Skip to content

Commit 2f6722b

Browse files
committed
Add array|int and object-of-class|int types to stubs
1 parent d57f9e5 commit 2f6722b

16 files changed

+351
-143
lines changed

Zend/zend_API.c

+26
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,12 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_error(int error_code,
225225
case ZPP_ERROR_WRONG_CLASS_OR_NULL:
226226
zend_wrong_parameter_class_or_null_error(num, name, arg);
227227
break;
228+
case ZPP_ERROR_WRONG_CLASS_OR_LONG:
229+
zend_wrong_parameter_class_or_long_error(num, name, arg);
230+
break;
231+
case ZPP_ERROR_WRONG_CLASS_OR_LONG_OR_NULL:
232+
zend_wrong_parameter_class_or_long_or_null_error(num, name, arg);
233+
break;
228234
case ZPP_ERROR_WRONG_ARG:
229235
zend_wrong_parameter_type_error(num, expected_type, arg);
230236
break;
@@ -278,6 +284,26 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_null_error(u
278284
}
279285
/* }}} */
280286

287+
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_long_error(uint32_t num, const char *name, zval *arg) /* {{{ */
288+
{
289+
if (EG(exception)) {
290+
return;
291+
}
292+
293+
zend_argument_type_error(num, "must be of type %s|int, %s given", name, zend_zval_type_name(arg));
294+
}
295+
/* }}} */
296+
297+
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_long_or_null_error(uint32_t num, const char *name, zval *arg) /* {{{ */
298+
{
299+
if (EG(exception)) {
300+
return;
301+
}
302+
303+
zend_argument_type_error(num, "must be of type %s|int|null, %s given", name, zend_zval_type_name(arg));
304+
}
305+
/* }}} */
306+
281307
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_string_or_class_error(uint32_t num, const char *name, zval *arg) /* {{{ */
282308
{
283309
if (EG(exception)) {

Zend/zend_API.h

+107-5
Original file line numberDiff line numberDiff line change
@@ -1209,6 +1209,8 @@ static zend_always_inline zval *zend_try_array_init(zval *zv)
12091209
_(Z_EXPECTED_STRING_OR_NULL, "of type ?string") \
12101210
_(Z_EXPECTED_ARRAY, "of type array") \
12111211
_(Z_EXPECTED_ARRAY_OR_NULL, "of type ?array") \
1212+
_(Z_EXPECTED_ARRAY_OR_LONG, "of type array|int") \
1213+
_(Z_EXPECTED_ARRAY_OR_LONG_OR_NULL, "of type array|int|null") \
12121214
_(Z_EXPECTED_ITERABLE, "of type iterable") \
12131215
_(Z_EXPECTED_ITERABLE_OR_NULL, "of type ?iterable") \
12141216
_(Z_EXPECTED_FUNC, "a valid callback") \
@@ -1248,6 +1250,8 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_error(int error_code,
12481250
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_type_error(uint32_t num, zend_expected_type expected_type, zval *arg);
12491251
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_error(uint32_t num, const char *name, zval *arg);
12501252
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_null_error(uint32_t num, const char *name, zval *arg);
1253+
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_long_error(uint32_t num, const char *name, zval *arg);
1254+
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_long_or_null_error(uint32_t num, const char *name, zval *arg);
12511255
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_string_or_class_error(uint32_t num, const char *name, zval *arg);
12521256
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_string_or_class_or_null_error(uint32_t num, const char *name, zval *arg);
12531257
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(uint32_t num, char *error);
@@ -1261,11 +1265,13 @@ ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *
12611265
#define ZPP_ERROR_WRONG_CALLBACK 2
12621266
#define ZPP_ERROR_WRONG_CLASS 3
12631267
#define ZPP_ERROR_WRONG_CLASS_OR_NULL 4
1264-
#define ZPP_ERROR_WRONG_ARG 5
1265-
#define ZPP_ERROR_WRONG_COUNT 6
1266-
#define ZPP_ERROR_WRONG_STRING_OR_CLASS 7
1267-
#define ZPP_ERROR_WRONG_STRING_OR_CLASS_OR_NULL 8
1268-
#define ZPP_ERROR_UNEXPECTED_EXTRA_NAMED 9
1268+
#define ZPP_ERROR_WRONG_CLASS_OR_LONG 5
1269+
#define ZPP_ERROR_WRONG_CLASS_OR_LONG_OR_NULL 6
1270+
#define ZPP_ERROR_WRONG_ARG 7
1271+
#define ZPP_ERROR_WRONG_COUNT 8
1272+
#define ZPP_ERROR_WRONG_STRING_OR_CLASS 9
1273+
#define ZPP_ERROR_WRONG_STRING_OR_CLASS_OR_NULL 10
1274+
#define ZPP_ERROR_UNEXPECTED_EXTRA_NAMED 11
12691275

12701276
#define ZEND_PARSE_PARAMETERS_START_EX(flags, min_num_args, max_num_args) do { \
12711277
const int _flags = (flags); \
@@ -1530,6 +1536,20 @@ ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *
15301536
#define Z_PARAM_ARRAY_HT_OR_NULL(dest) \
15311537
Z_PARAM_ARRAY_HT_EX(dest, 1, 0)
15321538

1539+
#define Z_PARAM_ARRAY_HT_OR_LONG_EX(dest_ht, dest_long, is_null, allow_null) \
1540+
Z_PARAM_PROLOGUE(0, 0); \
1541+
if (UNEXPECTED(!zend_parse_arg_array_ht_or_long(_arg, &dest_ht, &dest_long, &is_null, allow_null))) { \
1542+
_expected_type = allow_null ? Z_EXPECTED_ARRAY_OR_LONG_OR_NULL : Z_EXPECTED_ARRAY_OR_LONG; \
1543+
_error_code = ZPP_ERROR_WRONG_ARG; \
1544+
break; \
1545+
}
1546+
1547+
#define Z_PARAM_ARRAY_HT_OR_LONG(dest_ht, dest_long) \
1548+
Z_PARAM_ARRAY_HT_OR_LONG_EX(dest_ht, dest_long, _dummy, 0)
1549+
1550+
#define Z_PARAM_ARRAY_HT_OR_LONG_OR_NULL(dest_ht, dest_long, is_null) \
1551+
Z_PARAM_ARRAY_HT_OR_LONG_EX(dest_ht, dest_long, is_null, 1)
1552+
15331553
/* old "H" */
15341554
#define Z_PARAM_ARRAY_OR_OBJECT_HT_EX2(dest, check_null, deref, separate) \
15351555
Z_PARAM_PROLOGUE(deref, separate); \
@@ -1638,6 +1658,44 @@ ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *
16381658
#define Z_PARAM_OBJECT_OF_CLASS_OR_NULL(dest, _ce) \
16391659
Z_PARAM_OBJECT_OF_CLASS_EX(dest, _ce, 1, 0)
16401660

1661+
/* The same as Z_PARAM_OBJECT_OF_CLASS_EX2 except that dest is a zend_object rather than a zval */
1662+
#define Z_PARAM_OBJ_OF_CLASS_EX2(dest, _ce, check_null, deref, separate) \
1663+
Z_PARAM_PROLOGUE(deref, separate); \
1664+
if (UNEXPECTED(!zend_parse_arg_obj(_arg, &dest, _ce, check_null))) { \
1665+
if (_ce) { \
1666+
_error = ZSTR_VAL((_ce)->name); \
1667+
_error_code = check_null ? ZPP_ERROR_WRONG_CLASS_OR_NULL : ZPP_ERROR_WRONG_CLASS; \
1668+
break; \
1669+
} else { \
1670+
_expected_type = check_null ? Z_EXPECTED_OBJECT_OR_NULL : Z_EXPECTED_OBJECT; \
1671+
_error_code = ZPP_ERROR_WRONG_ARG; \
1672+
break; \
1673+
} \
1674+
}
1675+
1676+
#define Z_PARAM_OBJ_OF_CLASS_EX(dest, _ce, check_null, separate) \
1677+
Z_PARAM_OBJ_OF_CLASS_EX2(dest, _ce, check_null, separate, separate)
1678+
1679+
#define Z_PARAM_OBJ_OF_CLASS(dest, _ce) \
1680+
Z_PARAM_OBJ_OF_CLASS_EX(dest, _ce, 0, 0)
1681+
1682+
#define Z_PARAM_OBJ_OF_CLASS_OR_NULL(dest, _ce) \
1683+
Z_PARAM_OBJ_OF_CLASS_EX(dest, _ce, 1, 0)
1684+
1685+
#define Z_PARAM_OBJ_OF_CLASS_OR_LONG_EX(dest_obj, _ce, dest_long, is_null, allow_null) \
1686+
Z_PARAM_PROLOGUE(0, 0); \
1687+
if (UNEXPECTED(!zend_parse_arg_obj_or_long(_arg, &dest_obj, _ce, &dest_long, &is_null, allow_null))) { \
1688+
_error = ZSTR_VAL((_ce)->name); \
1689+
_error_code = allow_null ? ZPP_ERROR_WRONG_CLASS_OR_LONG_OR_NULL : ZPP_ERROR_WRONG_CLASS_OR_LONG; \
1690+
break; \
1691+
}
1692+
1693+
#define Z_PARAM_OBJ_OF_CLASS_OR_LONG(dest_obj, _ce, dest_long) \
1694+
Z_PARAM_OBJ_OF_CLASS_OR_LONG_EX(dest_obj, _ce, dest_long, _dummy, 0)
1695+
1696+
#define Z_PARAM_OBJ_OF_CLASS_OR_LONG_OR_NULL(dest_obj, _ce, dest_long, is_null) \
1697+
Z_PARAM_OBJ_OF_CLASS_OR_LONG_EX(dest_obj, _ce, dest_long, is_null, 1)
1698+
16411699
/* old "p" */
16421700
#define Z_PARAM_PATH_EX2(dest, dest_len, check_null, deref, separate) \
16431701
Z_PARAM_PROLOGUE(deref, separate); \
@@ -1991,6 +2049,28 @@ static zend_always_inline bool zend_parse_arg_array_ht(zval *arg, HashTable **de
19912049
return 1;
19922050
}
19932051

2052+
static zend_always_inline bool zend_parse_arg_array_ht_or_long(
2053+
zval *arg, HashTable **dest_ht, zend_long *dest_long, zend_bool *is_null, bool allow_null
2054+
) {
2055+
if (allow_null) {
2056+
*is_null = 0;
2057+
}
2058+
2059+
if (EXPECTED(Z_TYPE_P(arg) == IS_ARRAY)) {
2060+
*dest_ht = Z_ARRVAL_P(arg);
2061+
} else if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) {
2062+
*dest_ht = NULL;
2063+
*dest_long = Z_LVAL_P(arg);
2064+
} else if (allow_null && EXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
2065+
*dest_ht = NULL;
2066+
*is_null = 1;
2067+
} else {
2068+
return zend_parse_arg_long_slow(arg, dest_long);
2069+
}
2070+
2071+
return 1;
2072+
}
2073+
19942074
static zend_always_inline bool zend_parse_arg_object(zval *arg, zval **dest, zend_class_entry *ce, bool check_null)
19952075
{
19962076
if (EXPECTED(Z_TYPE_P(arg) == IS_OBJECT) &&
@@ -2017,6 +2097,28 @@ static zend_always_inline bool zend_parse_arg_obj(zval *arg, zend_object **dest,
20172097
return 1;
20182098
}
20192099

2100+
static zend_always_inline bool zend_parse_arg_obj_or_long(
2101+
zval *arg, zend_object **dest_obj, zend_class_entry *ce, zend_long *dest_long, zend_bool *is_null, bool allow_null
2102+
) {
2103+
if (allow_null) {
2104+
*is_null = 0;
2105+
}
2106+
2107+
if (EXPECTED(Z_TYPE_P(arg) == IS_OBJECT) && EXPECTED(instanceof_function(Z_OBJCE_P(arg), ce) != 0)) {
2108+
*dest_obj = Z_OBJ_P(arg);
2109+
} else if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) {
2110+
*dest_obj = NULL;
2111+
*dest_long = Z_LVAL_P(arg);
2112+
} else if (allow_null && EXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
2113+
*dest_obj = NULL;
2114+
*is_null = 1;
2115+
} else {
2116+
return zend_parse_arg_long_slow(arg, dest_long);
2117+
}
2118+
2119+
return 1;
2120+
}
2121+
20202122
static zend_always_inline bool zend_parse_arg_resource(zval *arg, zval **dest, bool check_null)
20212123
{
20222124
if (EXPECTED(Z_TYPE_P(arg) == IS_RESOURCE)) {

ext/date/php_date.c

+52-21
Original file line numberDiff line numberDiff line change
@@ -4108,30 +4108,49 @@ static int date_period_initialize(timelib_time **st, timelib_time **et, timelib_
41084108
/* {{{ Creates new DatePeriod object. */
41094109
PHP_METHOD(DatePeriod, __construct)
41104110
{
4111-
php_period_obj *dpobj;
4112-
php_date_obj *dateobj;
4113-
zval *start, *end = NULL, *interval;
4114-
zend_long recurrences = 0, options = 0;
4115-
char *isostr = NULL;
4116-
size_t isostr_len = 0;
4111+
php_period_obj *dpobj;
4112+
php_date_obj *dateobj;
4113+
zend_object *start_obj;
4114+
zend_string *start_str;
4115+
zend_object *interval_obj = NULL;
4116+
zend_bool interval_is_null = 1;
4117+
zend_object *end_obj = NULL;
4118+
zend_long recurrences = 0;
4119+
zend_bool end_is_null = 1;
4120+
zend_long options = 0;
4121+
char *isostr;
4122+
size_t isostr_len;
41174123
timelib_time *clone;
41184124
zend_error_handling error_handling;
41194125

41204126
zend_replace_error_handling(EH_THROW, NULL, &error_handling);
4121-
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "OOl|l", &start, date_ce_interface, &interval, date_ce_interval, &recurrences, &options) == FAILURE) {
4122-
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "OOO|l", &start, date_ce_interface, &interval, date_ce_interval, &end, date_ce_interface, &options) == FAILURE) {
4123-
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "s|l", &isostr, &isostr_len, &options) == FAILURE) {
4124-
php_error_docref(NULL, E_WARNING, "This constructor accepts either (DateTimeInterface, DateInterval, int) OR (DateTimeInterface, DateInterval, DateTime) OR (string) as arguments.");
4125-
zend_restore_error_handling(&error_handling);
4126-
return;
4127-
}
4128-
}
4129-
}
4127+
ZEND_PARSE_PARAMETERS_START(1, 4)
4128+
Z_PARAM_STR_OR_OBJ_OF_CLASS(start_str, start_obj, date_ce_interface)
4129+
Z_PARAM_OPTIONAL
4130+
Z_PARAM_OBJ_OF_CLASS_OR_LONG_OR_NULL(interval_obj, date_ce_interval, options, interval_is_null)
4131+
Z_PARAM_OBJ_OF_CLASS_OR_LONG_OR_NULL(end_obj, date_ce_interface, recurrences, end_is_null)
4132+
Z_PARAM_LONG(options)
4133+
ZEND_PARSE_PARAMETERS_END();
41304134

41314135
dpobj = Z_PHPPERIOD_P(ZEND_THIS);
41324136
dpobj->current = NULL;
41334137

4134-
if (isostr) {
4138+
if (start_str) {
4139+
if (interval_obj) {
4140+
zend_argument_type_error(2, "must be of type ?int when argument #1 ($start) is a string");
4141+
zend_restore_error_handling(&error_handling);
4142+
RETURN_THROWS();
4143+
}
4144+
4145+
if (!end_is_null) {
4146+
zend_argument_value_error(3, "must be null when argument #1 ($start) is a string");
4147+
zend_restore_error_handling(&error_handling);
4148+
RETURN_THROWS();
4149+
}
4150+
4151+
isostr = ZSTR_VAL(start_str);
4152+
isostr_len = ZSTR_LEN(start_str);
4153+
41354154
date_period_initialize(&(dpobj->start), &(dpobj->end), &(dpobj->interval), &recurrences, isostr, isostr_len);
41364155
if (dpobj->start == NULL) {
41374156
php_error_docref(NULL, E_WARNING, "The ISO interval '%s' did not contain a start date.", isostr);
@@ -4151,11 +4170,23 @@ PHP_METHOD(DatePeriod, __construct)
41514170
}
41524171
dpobj->start_ce = date_ce_date;
41534172
} else {
4173+
if (!interval_obj) {
4174+
zend_argument_type_error(2, "must be of type DateInterval when argument #1 ($start) is a DateTimeInterface");
4175+
zend_restore_error_handling(&error_handling);
4176+
RETURN_THROWS();
4177+
}
4178+
4179+
if (end_is_null) {
4180+
zend_argument_type_error(2, "must be of type DateTimeInterface|int when argument #1 ($start) is a DateTimeInterface");
4181+
zend_restore_error_handling(&error_handling);
4182+
RETURN_THROWS();
4183+
}
4184+
41544185
/* init */
4155-
php_interval_obj *intobj = Z_PHPINTERVAL_P(interval);
4186+
php_interval_obj *intobj = php_interval_obj_from_obj(interval_obj);
41564187

41574188
/* start date */
4158-
dateobj = Z_PHPDATE_P(start);
4189+
dateobj = php_date_obj_from_obj(start_obj);
41594190
clone = timelib_time_ctor();
41604191
memcpy(clone, dateobj->time, sizeof(timelib_time));
41614192
if (dateobj->time->tz_abbr) {
@@ -4165,14 +4196,14 @@ PHP_METHOD(DatePeriod, __construct)
41654196
clone->tz_info = dateobj->time->tz_info;
41664197
}
41674198
dpobj->start = clone;
4168-
dpobj->start_ce = Z_OBJCE_P(start);
4199+
dpobj->start_ce = start_obj->ce;
41694200

41704201
/* interval */
41714202
dpobj->interval = timelib_rel_time_clone(intobj->diff);
41724203

41734204
/* end date */
4174-
if (end) {
4175-
dateobj = Z_PHPDATE_P(end);
4205+
if (end_obj) {
4206+
dateobj = php_date_obj_from_obj(end_obj);
41764207
clone = timelib_time_clone(dateobj->time);
41774208
dpobj->end = clone;
41784209
}

ext/date/php_date.stub.php

+1-7
Original file line numberDiff line numberDiff line change
@@ -393,13 +393,7 @@ public static function __set_state(array $array) {}
393393

394394
class DatePeriod implements IteratorAggregate
395395
{
396-
/**
397-
* @param DateTimeInterface|string $start
398-
* @param DateInterval|int $interval
399-
* @param DateTimeInterface|int $end
400-
* @param int $options
401-
*/
402-
public function __construct($start, $interval = UNKNOWN, $end = UNKNOWN, $options = UNKNOWN) {}
396+
public function __construct(DateTimeInterface|string $start, DateInterval|int|null $interval = null, DateTimeInterface|int|null $end = null, int $options = 0) {}
403397

404398
/** @return DateTimeInterface */
405399
public function getStartDate() {}

ext/date/php_date_arginfo.h

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: fee95924adec03c89fdd677ec26bb6eea34d4b3c */
2+
* Stub hash: 67182d27266e8618e555e7617882166661f803b8 */
33

44
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_strtotime, 0, 1, MAY_BE_LONG|MAY_BE_FALSE)
55
ZEND_ARG_TYPE_INFO(0, datetime, IS_STRING, 0)
@@ -409,10 +409,10 @@ ZEND_END_ARG_INFO()
409409
#define arginfo_class_DateInterval___set_state arginfo_class_DateTime___set_state
410410

411411
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DatePeriod___construct, 0, 0, 1)
412-
ZEND_ARG_INFO(0, start)
413-
ZEND_ARG_INFO(0, interval)
414-
ZEND_ARG_INFO(0, end)
415-
ZEND_ARG_INFO(0, options)
412+
ZEND_ARG_OBJ_TYPE_MASK(0, start, DateTimeInterface, MAY_BE_STRING, NULL)
413+
ZEND_ARG_OBJ_TYPE_MASK(0, interval, DateInterval, MAY_BE_LONG|MAY_BE_NULL, "null")
414+
ZEND_ARG_OBJ_TYPE_MASK(0, end, DateTimeInterface, MAY_BE_LONG|MAY_BE_NULL, "null")
415+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_LONG, 0, "0")
416416
ZEND_END_ARG_INFO()
417417

418418
#define arginfo_class_DatePeriod_getStartDate arginfo_class_DateTimeInterface_getTimezone

ext/date/tests/DatePeriod_wrong_constructor.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ date.timezone=UTC
1010
new DatePeriod();
1111
?>
1212
--EXPECTF--
13-
Fatal error: Uncaught Exception: DatePeriod::__construct(): This constructor accepts either (DateTimeInterface, DateInterval, int) OR (DateTimeInterface, DateInterval, DateTime) OR (string) as arguments. in %s:%d
13+
Fatal error: Uncaught ArgumentCountError: DatePeriod::__construct() expects at least 1 parameter, 0 given in %s:%d
1414
Stack trace:
1515
#0 %s(%d): DatePeriod->__construct()
1616
#1 {main}

0 commit comments

Comments
 (0)