From b7860cd56476d737fcf2e1fdda109b042312e3fa Mon Sep 17 00:00:00 2001 From: Derick Rethans Date: Fri, 6 Jan 2023 15:31:16 +0000 Subject: [PATCH] Implement More Appropriate Date/Time Exceptions RFC --- NEWS | 3 + ext/date/php_date.c | 292 +++++++++++++----- ext/date/php_date.stub.php | 66 +++- ext/date/php_date_arginfo.h | 155 +++++++++- ext/date/tests/68062.phpt | 4 +- .../DateInterval_construct_exceptions.phpt | 21 ++ ...eInterval_createFromDateString_broken.phpt | 12 + .../tests/DateInterval_serialize-003.phpt | 17 +- .../DateInterval_set_state_exception.phpt | 22 ++ ...DateInterval_uninitialised_exceptions.phpt | 30 ++ .../tests/DatePeriod_by_ref_iterator.phpt | 22 ++ .../DatePeriod_modify_readonly_property.phpt | 25 ++ ext/date/tests/DatePeriod_properties2.phpt | 30 +- .../tests/DatePeriod_set_state_exception.phpt | 65 ++++ .../DatePeriod_uninitialised_exceptions.phpt | 45 +++ .../tests/DatePeriod_wrong_arguments.phpt | 25 ++ ...utable_createFromInterface_exceptions.phpt | 37 +++ ...teTimeImmutable_createFromMutable-001.phpt | 4 +- ...teTimeImmutable_createFromMutable-002.phpt | 4 +- ...mmutable_createFromMutable_exceptions.phpt | 23 ++ ...teTimeImmutable_modify_invalid_format.phpt | 9 +- ...DateTimeImmutable_set_state_exception.phpt | 38 +++ ...imeImmutable_uninitialised_exceptions.phpt | 79 +++++ ext/date/tests/DateTimeZone_compare.phpt | 46 +++ .../tests/DateTimeZone_compare_basic1.phpt | 14 +- .../tests/DateTimeZone_construct_error.phpt | 12 +- .../tests/DateTimeZone_serialize_errors.phpt | 7 +- .../DateTimeZone_set_state_exception.phpt | 38 +++ ...DateTimeZone_uninitialised_exceptions.phpt | 58 ++++ ext/date/tests/DateTime_compare.phpt | 48 +++ ext/date/tests/DateTime_construct_error.phpt | 12 +- .../DateTime_createFromImmutable-001.phpt | 4 +- .../DateTime_createFromImmutable-002.phpt | 4 +- .../tests/DateTime_modify_invalid_format.phpt | 18 ++ .../tests/DateTime_set_state_exception.phpt | 40 +++ .../DateTime_uninitialised_exceptions.phpt | 91 ++++++ ext/date/tests/DateTime_wakeup_exception.phpt | 34 ++ ext/date/tests/bug-gh8471.phpt | 8 +- ext/date/tests/bug-gh9763.phpt | 14 +- ext/date/tests/bug36988.phpt | 4 +- ext/date/tests/bug44562.phpt | 4 +- ext/date/tests/bug45866.phpt | 9 +- ext/date/tests/bug48476.phpt | 12 +- .../{bug50055.phpt => bug50055-001.phpt} | 4 +- ext/date/tests/bug50055-002.phpt | 36 +++ ext/date/tests/bug52062.phpt | 16 +- ext/date/tests/bug52808.phpt | 12 +- ext/date/tests/bug67118.phpt | 2 +- ext/date/tests/bug70245.phpt | 4 +- ext/date/tests/bug70277.phpt | 8 +- ext/date/tests/bug73239.phpt | 2 +- ext/date/tests/bug75002.phpt | 2 +- ext/date/tests/bug78139.phpt | 14 +- .../tests/date_interval_bad_format_leak.phpt | 12 +- ...terval_create_from_date_string_broken.phpt | 2 +- ...val_create_from_date_string_nullparam.phpt | 2 +- .../date_interval_non_relative_warning.phpt | 28 +- .../tests/date_period_bad_iso_format.phpt | 12 +- ext/date/tests/date_period_set_state2.phpt | 6 +- ext/date/tests/date_period_unserialize2.phpt | 6 +- ext/date/tests/date_period_unserialize3.phpt | 6 +- ext/date/tests/mktime_error.phpt | 12 +- ext/date/tests/oo_001.phpt | 26 +- ...ne_identifiers_list_wrong_constructor.phpt | 8 +- ext/date/tests/timezone_open_warning.phpt | 23 ++ .../tests/dateformat_formatObject_error.phpt | 2 +- 66 files changed, 1489 insertions(+), 261 deletions(-) create mode 100644 ext/date/tests/DateInterval_construct_exceptions.phpt create mode 100644 ext/date/tests/DateInterval_createFromDateString_broken.phpt create mode 100644 ext/date/tests/DateInterval_set_state_exception.phpt create mode 100644 ext/date/tests/DateInterval_uninitialised_exceptions.phpt create mode 100644 ext/date/tests/DatePeriod_by_ref_iterator.phpt create mode 100644 ext/date/tests/DatePeriod_modify_readonly_property.phpt create mode 100644 ext/date/tests/DatePeriod_set_state_exception.phpt create mode 100644 ext/date/tests/DatePeriod_uninitialised_exceptions.phpt create mode 100644 ext/date/tests/DatePeriod_wrong_arguments.phpt create mode 100644 ext/date/tests/DateTimeImmutable_createFromInterface_exceptions.phpt create mode 100644 ext/date/tests/DateTimeImmutable_createFromMutable_exceptions.phpt create mode 100644 ext/date/tests/DateTimeImmutable_set_state_exception.phpt create mode 100644 ext/date/tests/DateTimeImmutable_uninitialised_exceptions.phpt create mode 100644 ext/date/tests/DateTimeZone_compare.phpt create mode 100644 ext/date/tests/DateTimeZone_set_state_exception.phpt create mode 100644 ext/date/tests/DateTimeZone_uninitialised_exceptions.phpt create mode 100644 ext/date/tests/DateTime_compare.phpt create mode 100644 ext/date/tests/DateTime_modify_invalid_format.phpt create mode 100644 ext/date/tests/DateTime_set_state_exception.phpt create mode 100644 ext/date/tests/DateTime_uninitialised_exceptions.phpt create mode 100644 ext/date/tests/DateTime_wakeup_exception.phpt rename ext/date/tests/{bug50055.phpt => bug50055-001.phpt} (88%) create mode 100644 ext/date/tests/bug50055-002.phpt create mode 100644 ext/date/tests/timezone_open_warning.phpt diff --git a/NEWS b/NEWS index ad42da6774b2a..eea4bfe68969c 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,9 @@ PHP NEWS (ilutov) . Fix bug GH-10083 (Allow comments between & and parameter). (ilutov) +- Date: + . Implement More Appropriate Date/Time Exceptions RFC. (Derick) + - Exif: . Removed unneeded codepaths in exif_process_TIFF_in_JPEG(). (nielsdos) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 22353d6a7541c..350111c124a36 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -269,6 +269,8 @@ PHP_INI_END() zend_class_entry *date_ce_date, *date_ce_timezone, *date_ce_interval, *date_ce_period; zend_class_entry *date_ce_immutable, *date_ce_interface; +zend_class_entry *date_ce_date_error, *date_ce_date_object_error, *date_ce_date_range_error; +zend_class_entry *date_ce_date_exception, *date_ce_date_invalid_timezone_exception, *date_ce_date_invalid_operation_exception, *date_ce_date_malformed_string_exception, *date_ce_date_malformed_interval_string_exception, *date_ce_date_malformed_period_string_exception; PHPAPI zend_class_entry *php_date_get_date_ce(void) @@ -307,9 +309,25 @@ static zend_object_handlers date_object_handlers_timezone; static zend_object_handlers date_object_handlers_interval; static zend_object_handlers date_object_handlers_period; -#define DATE_CHECK_INITIALIZED(member, class_name) \ +static void date_throw_uninitialized_error(zend_class_entry *ce) +{ + if (ce->type == ZEND_INTERNAL_CLASS) { + zend_throw_error(date_ce_date_object_error, "Object of type %s has not been correctly initialized by calling parent::__construct() in its constructor", ZSTR_VAL(ce->name)); + } else { + zend_class_entry *ce_ptr = ce; + while (ce_ptr && ce_ptr->parent && ce_ptr->type == ZEND_USER_CLASS) { + ce_ptr = ce_ptr->parent; + } + if (ce_ptr->type != ZEND_INTERNAL_CLASS) { + zend_throw_error(date_ce_date_object_error, "Object of type %s not been correctly initialized by calling parent::__construct() in its constructor", ZSTR_VAL(ce->name)); + } + zend_throw_error(date_ce_date_object_error, "Object of type %s (inheriting %s) has not been correctly initialized by calling parent::__construct() in its constructor", ZSTR_VAL(ce->name), ZSTR_VAL(ce_ptr->name)); + } +} + +#define DATE_CHECK_INITIALIZED(member, ce) \ if (!(member)) { \ - zend_throw_error(NULL, "The " #class_name " object has not been correctly initialized by its constructor"); \ + date_throw_uninitialized_error(ce); \ RETURN_THROWS(); \ } @@ -561,7 +579,7 @@ PHPAPI timelib_tzinfo *get_timezone_info(void) tz = guess_timezone(DATE_TIMEZONEDB); tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB); if (! tzi) { - zend_throw_error(NULL, "Timezone database is corrupt. Please file a bug report as this should never happen"); + zend_throw_error(date_ce_date_error, "Timezone database is corrupt. Please file a bug report as this should never happen"); } return tzi; } @@ -1623,7 +1641,7 @@ static void date_period_it_rewind(zend_object_iterator *iter) timelib_time_dtor(iterator->object->current); } if (!iterator->object->start) { - zend_throw_error(NULL, "DatePeriod has not been initialized correctly"); + date_throw_uninitialized_error(date_ce_period); return; } @@ -1779,6 +1797,17 @@ static void date_register_classes(void) /* {{{ */ date_object_handlers_period.get_property_ptr_ptr = date_period_get_property_ptr_ptr; date_object_handlers_period.read_property = date_period_read_property; date_object_handlers_period.write_property = date_period_write_property; + + date_ce_date_error = register_class_DateError(zend_ce_error); + date_ce_date_object_error = register_class_DateObjectError(date_ce_date_error); + date_ce_date_range_error = register_class_DateRangeError(date_ce_date_error); + + date_ce_date_exception = register_class_DateException(zend_ce_exception); + date_ce_date_invalid_timezone_exception = register_class_DateInvalidTimeZoneException(date_ce_date_exception); + date_ce_date_invalid_operation_exception = register_class_DateInvalidOperationException(date_ce_date_exception); + date_ce_date_malformed_string_exception = register_class_DateMalformedStringException(date_ce_date_exception); + date_ce_date_malformed_interval_string_exception = register_class_DateMalformedIntervalStringException(date_ce_date_exception); + date_ce_date_malformed_period_string_exception = register_class_DateMalformedPeriodStringException(date_ce_date_exception); } /* }}} */ static zend_object *date_object_new_date(zend_class_entry *class_type) /* {{{ */ @@ -1830,7 +1859,7 @@ static int date_object_compare_date(zval *d1, zval *d2) /* {{{ */ o2 = Z_PHPDATE_P(d2); if (!o1->time || !o2->time) { - php_error_docref(NULL, E_WARNING, "Trying to compare an incomplete DateTime or DateTimeImmutable object"); + zend_throw_error(date_ce_date_object_error, "Trying to compare an incomplete DateTime or DateTimeImmutable object"); return ZEND_UNCOMPARABLE; } if (!o1->time->sse_uptodate) { @@ -1970,12 +1999,12 @@ static int date_object_compare_timezone(zval *tz1, zval *tz2) /* {{{ */ o2 = Z_PHPTIMEZONE_P(tz2); if (!o1->initialized || !o2->initialized) { - zend_throw_error(NULL, "Trying to compare uninitialized DateTimeZone objects"); + zend_throw_error(date_ce_date_object_error, "Trying to compare uninitialized DateTimeZone objects"); return 1; } if (o1->type != o2->type) { - php_error_docref(NULL, E_WARNING, "Trying to compare different kinds of DateTimeZone objects"); + zend_throw_error(date_ce_date_exception, "Cannot compare two different kinds of DateTimeZone objects"); return ZEND_UNCOMPARABLE; } @@ -2349,8 +2378,8 @@ PHPAPI bool php_date_initialize(php_date_obj *dateobj, const char *time_str, siz /* If called from a constructor throw an exception */ if ((flags & PHP_DATE_INIT_CTOR) && err && err->error_count) { /* spit out the first library error message, at least */ - zend_throw_exception_ex(NULL, 0, "Failed to parse time string (%s) at position %d (%c): %s", time_str, - err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message); + zend_throw_exception_ex(date_ce_date_malformed_string_exception, 0, "Failed to parse time string (%s) at position %d (%c): %s", time_str, + err->error_messages[0].position, err->error_messages[0].character ? err->error_messages[0].character : ' ', err->error_messages[0].message); } if (err && err->error_count) { timelib_time_dtor(dateobj->time); @@ -2560,7 +2589,7 @@ PHP_METHOD(DateTime, createFromImmutable) ZEND_PARSE_PARAMETERS_END(); old_obj = Z_PHPDATE_P(datetimeimmutable_object); - DATE_CHECK_INITIALIZED(old_obj->time, DateTimeImmutable); + DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetimeimmutable_object)); php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date, return_value); new_obj = Z_PHPDATE_P(return_value); @@ -2581,7 +2610,7 @@ PHP_METHOD(DateTime, createFromInterface) ZEND_PARSE_PARAMETERS_END(); old_obj = Z_PHPDATE_P(datetimeinterface_object); - DATE_CHECK_INITIALIZED(old_obj->time, DateTimeInterface); + DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetimeinterface_object)); php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date, return_value); new_obj = Z_PHPDATE_P(return_value); @@ -2602,7 +2631,7 @@ PHP_METHOD(DateTimeImmutable, createFromMutable) ZEND_PARSE_PARAMETERS_END(); old_obj = Z_PHPDATE_P(datetime_object); - DATE_CHECK_INITIALIZED(old_obj->time, DateTime); + DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetime_object)); php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable, return_value); new_obj = Z_PHPDATE_P(return_value); @@ -2623,7 +2652,7 @@ PHP_METHOD(DateTimeImmutable, createFromInterface) ZEND_PARSE_PARAMETERS_END(); old_obj = Z_PHPDATE_P(datetimeinterface_object); - DATE_CHECK_INITIALIZED(old_obj->time, DateTimeInterface); + DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetimeinterface_object)); php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable, return_value); new_obj = Z_PHPDATE_P(return_value); @@ -2741,7 +2770,7 @@ PHP_METHOD(DateTime, __serialize) ZEND_PARSE_PARAMETERS_NONE(); dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); array_init(return_value); myht = Z_ARRVAL_P(return_value); @@ -2761,7 +2790,7 @@ PHP_METHOD(DateTimeImmutable, __serialize) ZEND_PARSE_PARAMETERS_NONE(); dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTimeImmutable); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); array_init(return_value); myht = Z_ARRVAL_P(return_value); @@ -3034,7 +3063,7 @@ PHP_FUNCTION(date_format) RETURN_THROWS(); } dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); RETURN_STR(date_format(format, format_len, dateobj->time, dateobj->time->is_localtime)); } /* }}} */ @@ -3048,7 +3077,7 @@ static bool php_date_modify(zval *object, char *modify, size_t modify_len) /* {{ dateobj = Z_PHPDATE_P(object); if (!(dateobj->time)) { - zend_throw_error(NULL, "The DateTime object has not been correctly initialized by its constructor"); + date_throw_uninitialized_error(Z_OBJCE_P(object)); return 0; } @@ -3060,7 +3089,9 @@ static bool php_date_modify(zval *object, char *modify, size_t modify_len) /* {{ if (err && err->error_count) { /* spit out the first library error message, at least */ php_error_docref(NULL, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", modify, - err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message); + err->error_messages[0].position, + err->error_messages[0].character ? err->error_messages[0].character : ' ', + err->error_messages[0].message); timelib_time_dtor(tmp_time); return 0; } @@ -3131,12 +3162,38 @@ PHP_FUNCTION(date_modify) } /* }}} */ +/* {{{ */ +PHP_METHOD(DateTime, modify) +{ + zval *object; + char *modify; + size_t modify_len; + zend_error_handling zeh; + + object = ZEND_THIS; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &modify, &modify_len) == FAILURE) { + RETURN_THROWS(); + } + + zend_replace_error_handling(EH_THROW, date_ce_date_malformed_string_exception, &zeh); + if (!php_date_modify(object, modify, modify_len)) { + zend_restore_error_handling(&zeh); + RETURN_THROWS(); + } + + zend_restore_error_handling(&zeh); + + RETURN_OBJ_COPY(Z_OBJ_P(object)); +} +/* }}} */ + /* {{{ */ PHP_METHOD(DateTimeImmutable, modify) { zval *object, new_object; char *modify; size_t modify_len; + zend_error_handling zeh; object = ZEND_THIS; if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &modify, &modify_len) == FAILURE) { @@ -3144,11 +3201,16 @@ PHP_METHOD(DateTimeImmutable, modify) } date_clone_immutable(object, &new_object); + + zend_replace_error_handling(EH_THROW, date_ce_date_malformed_string_exception, &zeh); if (!php_date_modify(&new_object, modify, modify_len)) { zval_ptr_dtor(&new_object); - RETURN_FALSE; + zend_restore_error_handling(&zeh); + RETURN_THROWS(); } + zend_restore_error_handling(&zeh); + RETURN_OBJ(Z_OBJ(new_object)); } /* }}} */ @@ -3160,9 +3222,9 @@ static void php_date_add(zval *object, zval *interval, zval *return_value) /* {{ timelib_time *new_time; dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); intobj = Z_PHPINTERVAL_P(interval); - DATE_CHECK_INITIALIZED(intobj->initialized, DateInterval); + DATE_CHECK_INITIALIZED(intobj->initialized, Z_OBJCE_P(interval)); if (intobj->civil_or_wall == PHP_DATE_WALL) { new_time = timelib_add_wall(dateobj->time, intobj->diff); @@ -3212,9 +3274,9 @@ static void php_date_sub(zval *object, zval *interval, zval *return_value) /* {{ timelib_time *new_time; dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); intobj = Z_PHPINTERVAL_P(interval); - DATE_CHECK_INITIALIZED(intobj->initialized, DateInterval); + DATE_CHECK_INITIALIZED(intobj->initialized, Z_OBJCE_P(interval)); if (intobj->diff->have_weekday_relative || intobj->diff->have_special_relative) { php_error_docref(NULL, E_WARNING, "Only non-special relative time specifications are supported for subtraction"); @@ -3240,6 +3302,23 @@ PHP_FUNCTION(date_sub) } php_date_sub(object, interval, return_value); + RETURN_OBJ_COPY(Z_OBJ_P(object)); +} +/* }}} */ + +/* {{{ Subtracts an interval to the current date in object. */ +PHP_METHOD(DateTime, sub) +{ + zval *object, *interval; + zend_error_handling zeh; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) { + RETURN_THROWS(); + } + + zend_replace_error_handling(EH_THROW, date_ce_date_invalid_operation_exception, &zeh); + php_date_sub(object, interval, return_value); + zend_restore_error_handling(&zeh); RETURN_OBJ_COPY(Z_OBJ_P(object)); } @@ -3249,6 +3328,7 @@ PHP_FUNCTION(date_sub) PHP_METHOD(DateTimeImmutable, sub) { zval *object, *interval, new_object; + zend_error_handling zeh; object = ZEND_THIS; if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &interval, date_ce_interval) == FAILURE) { @@ -3256,7 +3336,10 @@ PHP_METHOD(DateTimeImmutable, sub) } date_clone_immutable(object, &new_object); + + zend_replace_error_handling(EH_THROW, date_ce_date_invalid_operation_exception, &zeh); php_date_sub(&new_object, interval, return_value); + zend_restore_error_handling(&zeh); RETURN_OBJ(Z_OBJ(new_object)); } @@ -3299,7 +3382,7 @@ PHP_FUNCTION(date_timezone_get) RETURN_THROWS(); } dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); if (dateobj->time->is_localtime) { php_timezone_obj *tzobj; php_date_instantiate(date_ce_timezone, return_value); @@ -3317,7 +3400,7 @@ static void php_date_timezone_set(zval *object, zval *timezone_object, zval *ret php_timezone_obj *tzobj; dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); tzobj = Z_PHPTIMEZONE_P(timezone_object); switch (tzobj->type) { @@ -3379,7 +3462,7 @@ PHP_FUNCTION(date_offset_get) RETURN_THROWS(); } dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); if (dateobj->time->is_localtime) { switch (dateobj->time->zone_type) { case TIMELIB_ZONETYPE_ID: @@ -3406,7 +3489,7 @@ static void php_date_time_set(zval *object, zend_long h, zend_long i, zend_long php_date_obj *dateobj; dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); dateobj->time->h = h; dateobj->time->i = i; dateobj->time->s = s; @@ -3454,7 +3537,7 @@ static void php_date_date_set(zval *object, zend_long y, zend_long m, zend_long php_date_obj *dateobj; dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); dateobj->time->y = y; dateobj->time->m = m; dateobj->time->d = d; @@ -3500,7 +3583,7 @@ static void php_date_isodate_set(zval *object, zend_long y, zend_long w, zend_lo php_date_obj *dateobj; dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); dateobj->time->y = y; dateobj->time->m = 1; dateobj->time->d = 1; @@ -3550,7 +3633,7 @@ static void php_date_timestamp_set(zval *object, zend_long timestamp, zval *retu php_date_obj *dateobj; dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); timelib_unixtime2local(dateobj->time, (timelib_sll)timestamp); timelib_update_ts(dateobj->time, NULL); php_date_set_time_fraction(dateobj->time, 0); @@ -3602,7 +3685,7 @@ PHP_FUNCTION(date_timestamp_get) RETURN_THROWS(); } dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); if (!dateobj->time->sse_uptodate) { timelib_update_ts(dateobj->time, NULL); @@ -3611,7 +3694,7 @@ PHP_FUNCTION(date_timestamp_get) timestamp = timelib_date_to_int(dateobj->time, &epoch_does_not_fit_in_zend_long); if (epoch_does_not_fit_in_zend_long) { - zend_value_error("Epoch doesn't fit in a PHP integer"); + zend_throw_error(date_ce_date_range_error, "Epoch doesn't fit in a PHP integer"); RETURN_THROWS(); } @@ -3632,8 +3715,8 @@ PHP_FUNCTION(date_diff) } dateobj1 = Z_PHPDATE_P(object1); dateobj2 = Z_PHPDATE_P(object2); - DATE_CHECK_INITIALIZED(dateobj1->time, DateTimeInterface); - DATE_CHECK_INITIALIZED(dateobj2->time, DateTimeInterface); + DATE_CHECK_INITIALIZED(dateobj1->time, Z_OBJCE_P(object1)); + DATE_CHECK_INITIALIZED(dateobj2->time, Z_OBJCE_P(object2)); php_date_instantiate(date_ce_interval, return_value); interval = Z_PHPINTERVAL_P(return_value); @@ -3646,34 +3729,42 @@ PHP_FUNCTION(date_diff) } /* }}} */ -static bool timezone_initialize(php_timezone_obj *tzobj, const char *tz, size_t tz_len) /* {{{ */ +static bool timezone_initialize(php_timezone_obj *tzobj, const char *tz, size_t tz_len, char **warning_message) /* {{{ */ { timelib_time *dummy_t = ecalloc(1, sizeof(timelib_time)); int dst, not_found; const char *orig_tz = tz; if (strlen(tz) != tz_len) { - php_error_docref(NULL, E_WARNING, "Timezone must not contain null bytes"); + if (warning_message) { + spprintf(warning_message, 0, "Timezone must not contain null bytes"); + } efree(dummy_t); return false; } dummy_t->z = timelib_parse_zone(&tz, &dst, dummy_t, ¬_found, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); if ((dummy_t->z >= (100 * 60 * 60)) || (dummy_t->z <= (-100 * 60 * 60))) { - php_error_docref(NULL, E_WARNING, "Timezone offset is out of range (%s)", orig_tz); + if (warning_message) { + spprintf(warning_message, 0, "Timezone offset is out of range (%s)", orig_tz); + } timelib_free(dummy_t->tz_abbr); efree(dummy_t); - return FAILURE; + return false; } dummy_t->dst = dst; if (!not_found && (*tz != '\0')) { - php_error_docref(NULL, E_WARNING, "Unknown or bad timezone (%s)", orig_tz); + if (warning_message) { + spprintf(warning_message, 0, "Unknown or bad timezone (%s)", orig_tz); + } timelib_free(dummy_t->tz_abbr); efree(dummy_t); return false; } if (not_found) { - php_error_docref(NULL, E_WARNING, "Unknown or bad timezone (%s)", orig_tz); + if (warning_message) { + spprintf(warning_message, 0, "Unknown or bad timezone (%s)", orig_tz); + } efree(dummy_t); return false; } else { @@ -3689,13 +3780,16 @@ PHP_FUNCTION(timezone_open) { zend_string *tz; php_timezone_obj *tzobj; + char *warning_message; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_PATH_STR(tz) /* To prevent null bytes */ ZEND_PARSE_PARAMETERS_END(); tzobj = Z_PHPTIMEZONE_P(php_date_instantiate(date_ce_timezone, return_value)); - if (!timezone_initialize(tzobj, ZSTR_VAL(tz), ZSTR_LEN(tz))) { + if (!timezone_initialize(tzobj, ZSTR_VAL(tz), ZSTR_LEN(tz), &warning_message)) { + php_error_docref(NULL, E_WARNING, "%s", warning_message); + efree(warning_message); zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3707,16 +3801,17 @@ PHP_METHOD(DateTimeZone, __construct) { zend_string *tz; php_timezone_obj *tzobj; - zend_error_handling error_handling; + char *exception_message; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_PATH_STR(tz) /* To prevent null bytes */ ZEND_PARSE_PARAMETERS_END(); - zend_replace_error_handling(EH_THROW, NULL, &error_handling); tzobj = Z_PHPTIMEZONE_P(ZEND_THIS); - timezone_initialize(tzobj, ZSTR_VAL(tz), ZSTR_LEN(tz)); - zend_restore_error_handling(&error_handling); + if (!timezone_initialize(tzobj, ZSTR_VAL(tz), ZSTR_LEN(tz), &exception_message)) { + zend_throw_exception_ex(date_ce_date_invalid_timezone_exception, 0, "DateTimeZone::__construct(): %s", exception_message); + efree(exception_message); + } } /* }}} */ @@ -3737,10 +3832,13 @@ static bool php_date_timezone_initialize_from_hash(zval **return_value, php_time if (Z_TYPE_P(z_timezone_type) != IS_LONG) { return false; } + if (Z_LVAL_P(z_timezone_type) < TIMELIB_ZONETYPE_OFFSET || Z_LVAL_P(z_timezone_type) > TIMELIB_ZONETYPE_ID) { + return false; + } if (Z_TYPE_P(z_timezone) != IS_STRING) { return false; } - return timezone_initialize(*tzobj, Z_STRVAL_P(z_timezone), Z_STRLEN_P(z_timezone)); + return timezone_initialize(*tzobj, Z_STRVAL_P(z_timezone), Z_STRLEN_P(z_timezone), NULL); } /* }}} */ /* {{{ */ @@ -3759,8 +3857,7 @@ PHP_METHOD(DateTimeZone, __set_state) php_date_instantiate(date_ce_timezone, return_value); tzobj = Z_PHPTIMEZONE_P(return_value); if (!php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht)) { - zend_throw_error(NULL, "Timezone initialization failed"); - zval_ptr_dtor(return_value); + zend_throw_error(NULL, "Invalid serialization data for DateTimeZone object"); } } /* }}} */ @@ -3779,7 +3876,7 @@ PHP_METHOD(DateTimeZone, __wakeup) myht = Z_OBJPROP_P(object); if (!php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht)) { - zend_throw_error(NULL, "Timezone initialization failed"); + zend_throw_error(NULL, "Invalid serialization data for DateTimeZone object"); } } /* }}} */ @@ -3794,7 +3891,7 @@ PHP_METHOD(DateTimeZone, __serialize) ZEND_PARSE_PARAMETERS_NONE(); tzobj = Z_PHPTIMEZONE_P(object); - DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone); + DATE_CHECK_INITIALIZED(tzobj->initialized, Z_OBJCE_P(object)); array_init(return_value); myht = Z_ARRVAL_P(return_value); @@ -3861,7 +3958,7 @@ PHP_FUNCTION(timezone_name_get) RETURN_THROWS(); } tzobj = Z_PHPTIMEZONE_P(object); - DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone); + DATE_CHECK_INITIALIZED(tzobj->initialized, Z_OBJCE_P(object)); php_timezone_to_string(tzobj, return_value); } /* }}} */ @@ -3903,9 +4000,9 @@ PHP_FUNCTION(timezone_offset_get) RETURN_THROWS(); } tzobj = Z_PHPTIMEZONE_P(object); - DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone); + DATE_CHECK_INITIALIZED(tzobj->initialized, Z_OBJCE_P(object)); dateobj = Z_PHPDATE_P(dateobject); - DATE_CHECK_INITIALIZED(dateobj->time, DateTimeInterface); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(dateobject)); switch (tzobj->type) { case TIMELIB_ZONETYPE_ID: @@ -3936,7 +4033,7 @@ PHP_FUNCTION(timezone_transitions_get) RETURN_THROWS(); } tzobj = Z_PHPTIMEZONE_P(object); - DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone); + DATE_CHECK_INITIALIZED(tzobj->initialized, Z_OBJCE_P(object)); if (tzobj->type != TIMELIB_ZONETYPE_ID) { RETURN_FALSE; } @@ -4069,7 +4166,7 @@ PHP_FUNCTION(timezone_location_get) RETURN_THROWS(); } tzobj = Z_PHPTIMEZONE_P(object); - DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone); + DATE_CHECK_INITIALIZED(tzobj->initialized, Z_OBJCE_P(object)); if (tzobj->type != TIMELIB_ZONETYPE_ID) { RETURN_FALSE; } @@ -4093,23 +4190,23 @@ static bool date_interval_initialize(timelib_rel_time **rt, /*const*/ char *form timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors); if (errors->error_count > 0) { - zend_throw_exception_ex(NULL, 0, "Unknown or bad format (%s)", format); + zend_throw_exception_ex(date_ce_date_malformed_interval_string_exception, 0, "Unknown or bad format (%s)", format); retval = false; if (p) { timelib_rel_time_dtor(p); } } else { - if(p) { + if (p) { *rt = p; retval = true; } else { - if(b && e) { + if (b && e) { timelib_update_ts(b, NULL); timelib_update_ts(e, NULL); *rt = timelib_diff(b, e); retval = true; } else { - zend_throw_exception_ex(NULL, 0, "Failed to parse interval (%s)", format); + zend_throw_exception_ex(date_ce_date_malformed_interval_string_exception, 0, "Failed to parse interval (%s)", format); retval = false; } } @@ -4281,8 +4378,7 @@ static void php_date_interval_initialize_from_hash(zval **return_value, php_inte time = timelib_strtotime(Z_STRVAL_P(date_str), Z_STRLEN_P(date_str), &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); if (err->error_count > 0) { - php_error_docref(NULL, - E_WARNING, + zend_throw_error(NULL, "Unknown or bad format (%s) at position %d (%c) while unserializing: %s", Z_STRVAL_P(date_str), err->error_messages[0].position, @@ -4413,7 +4509,7 @@ PHP_METHOD(DateInterval, __serialize) ZEND_PARSE_PARAMETERS_NONE(); intervalobj = Z_PHPINTERVAL_P(object); - DATE_CHECK_INITIALIZED(intervalobj->initialized, DateInterval); + DATE_CHECK_INITIALIZED(intervalobj->initialized, Z_OBJCE_P(object)); array_init(return_value); myht = Z_ARRVAL_P(return_value); @@ -4494,13 +4590,25 @@ PHP_METHOD(DateInterval, __wakeup) } /* }}} */ +static void date_interval_instantiate_from_time(zval *return_value, timelib_time *time, zend_string *time_str) +{ + php_interval_obj *diobj; + + php_date_instantiate(date_ce_interval, return_value); + diobj = Z_PHPINTERVAL_P(return_value); + diobj->diff = timelib_rel_time_clone(&time->relative); + diobj->initialized = 1; + diobj->civil_or_wall = PHP_DATE_CIVIL; + diobj->from_string = true; + diobj->date_string = zend_string_copy(time_str); +} + /* {{{ Uses the normal date parsers and sets up a DateInterval from the relative parts of the parsed string */ PHP_FUNCTION(date_interval_create_from_date_string) { zend_string *time_str = NULL; timelib_time *time; timelib_error_container *err = NULL; - php_interval_obj *diobj; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STR(time_str) @@ -4521,13 +4629,39 @@ PHP_FUNCTION(date_interval_create_from_date_string) goto cleanup; } - php_date_instantiate(date_ce_interval, return_value); - diobj = Z_PHPINTERVAL_P(return_value); - diobj->diff = timelib_rel_time_clone(&time->relative); - diobj->initialized = 1; - diobj->civil_or_wall = PHP_DATE_CIVIL; - diobj->from_string = true; - diobj->date_string = zend_string_copy(time_str); + date_interval_instantiate_from_time(return_value, time, time_str); + +cleanup: + timelib_time_dtor(time); + timelib_error_container_dtor(err); +} +/* }}} */ + +/* {{{ Uses the normal date parsers and sets up a DateInterval from the relative parts of the parsed string */ +PHP_METHOD(DateInterval, createFromDateString) +{ + zend_string *time_str = NULL; + timelib_time *time; + timelib_error_container *err = NULL; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(time_str) + ZEND_PARSE_PARAMETERS_END(); + + time = timelib_strtotime(ZSTR_VAL(time_str), ZSTR_LEN(time_str), &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); + + if (err->error_count > 0) { + zend_throw_error(date_ce_date_malformed_interval_string_exception, "Unknown or bad format (%s) at position %d (%c): %s", ZSTR_VAL(time_str), + err->error_messages[0].position, err->error_messages[0].character ? err->error_messages[0].character : ' ', err->error_messages[0].message); + goto cleanup; + } + + if (time->have_date || time->have_time || time->have_zone) { + zend_throw_error(date_ce_date_malformed_interval_string_exception, "String '%s' contains non-relative elements", ZSTR_VAL(time_str)); + goto cleanup; + } + + date_interval_instantiate_from_time(return_value, time, time_str); cleanup: timelib_time_dtor(time); @@ -4617,7 +4751,7 @@ PHP_FUNCTION(date_interval_format) RETURN_THROWS(); } diobj = Z_PHPINTERVAL_P(object); - DATE_CHECK_INITIALIZED(diobj->initialized, DateInterval); + DATE_CHECK_INITIALIZED(diobj->initialized, Z_OBJCE_P(object)); RETURN_STR(date_interval_format(format, format_len, diobj->diff)); } @@ -4635,7 +4769,7 @@ static bool date_period_initialize(timelib_time **st, timelib_time **et, timelib if (errors->error_count > 0) { retval = false; - zend_throw_exception_ex(NULL, 0, "Unknown or bad format (%s)", format); + zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "Unknown or bad format (%s)", format); if (b) { timelib_time_dtor(b); } @@ -4686,19 +4820,19 @@ PHP_METHOD(DatePeriod, __construct) if (dpobj->start == NULL) { zend_string *func = get_active_function_or_method_name(); - zend_throw_exception_ex(NULL, 0, "%s(): ISO interval must contain a start date, \"%s\" given", ZSTR_VAL(func), isostr); + zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): ISO interval must contain a start date, \"%s\" given", ZSTR_VAL(func), isostr); zend_string_release(func); RETURN_THROWS(); } if (dpobj->interval == NULL) { zend_string *func = get_active_function_or_method_name(); - zend_throw_exception_ex(NULL, 0, "%s(): ISO interval must contain an interval, \"%s\" given", ZSTR_VAL(func), isostr); + zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): ISO interval must contain an interval, \"%s\" given", ZSTR_VAL(func), isostr); zend_string_release(func); RETURN_THROWS(); } if (dpobj->end == NULL && recurrences == 0) { zend_string *func = get_active_function_or_method_name(); - zend_throw_exception_ex(NULL, 0, "%s(): ISO interval must contain an end date or a recurrence count, \"%s\" given", ZSTR_VAL(func), isostr); + zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): ISO interval must contain an end date or a recurrence count, \"%s\" given", ZSTR_VAL(func), isostr); zend_string_release(func); RETURN_THROWS(); } @@ -4740,7 +4874,7 @@ PHP_METHOD(DatePeriod, __construct) if (dpobj->end == NULL && recurrences < 1) { zend_string *func = get_active_function_or_method_name(); - zend_throw_exception_ex(NULL, 0, "%s(): Recurrence count must be greater than 0", ZSTR_VAL(func)); + zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): Recurrence count must be greater than 0", ZSTR_VAL(func)); zend_string_release(func); RETURN_THROWS(); } @@ -4767,7 +4901,7 @@ PHP_METHOD(DatePeriod, getStartDate) ZEND_PARSE_PARAMETERS_NONE(); dpobj = Z_PHPPERIOD_P(ZEND_THIS); - DATE_CHECK_INITIALIZED(dpobj->start, DatePeriod); + DATE_CHECK_INITIALIZED(dpobj->start, Z_OBJCE_P(ZEND_THIS)); php_date_instantiate(dpobj->start_ce, return_value); dateobj = Z_PHPDATE_P(return_value); @@ -4818,7 +4952,7 @@ PHP_METHOD(DatePeriod, getDateInterval) ZEND_PARSE_PARAMETERS_NONE(); dpobj = Z_PHPPERIOD_P(ZEND_THIS); - DATE_CHECK_INITIALIZED(dpobj->interval, DatePeriod); + DATE_CHECK_INITIALIZED(dpobj->interval, Z_OBJCE_P(ZEND_THIS)); php_date_instantiate(date_ce_interval, return_value); diobj = Z_PHPINTERVAL_P(return_value); @@ -5374,7 +5508,7 @@ PHP_METHOD(DatePeriod, __serialize) ZEND_PARSE_PARAMETERS_NONE(); period_obj = Z_PHPPERIOD_P(object); - DATE_CHECK_INITIALIZED(period_obj->start, DatePeriod); + DATE_CHECK_INITIALIZED(period_obj->start, Z_OBJCE_P(object)); array_init(return_value); myht = Z_ARRVAL_P(return_value); diff --git a/ext/date/php_date.stub.php b/ext/date/php_date.stub.php index 172ab6d8b1d22..0146704e42a0b 100644 --- a/ext/date/php_date.stub.php +++ b/ext/date/php_date.stub.php @@ -377,7 +377,6 @@ public function format(string $format): string {} /** * @tentative-return-type - * @alias date_modify */ public function modify(string $modifier): DateTime|false {} @@ -389,7 +388,6 @@ public function add(DateInterval $interval): DateTime {} /** * @tentative-return-type - * @alias date_sub */ public function sub(DateInterval $interval): DateTime {} @@ -668,7 +666,6 @@ public function __construct(string $duration) {} /** * @tentative-return-type - * @alias date_interval_create_from_date_string */ public static function createFromDateString(string $datetime): DateInterval|false {} @@ -749,3 +746,66 @@ public static function __set_state(array $array): DatePeriod {} public function getIterator(): Iterator {} } + +/** + * @strict-properties + */ +class DateError extends Error +{ +} + +/** + * @strict-properties + */ +class DateObjectError extends DateError +{ +} + +/** + * @strict-properties + */ +class DateRangeError extends DateRangeError +{ +} + +/** + * @strict-properties + */ +class DateException extends Exception +{ +} + +/** + * @strict-properties + */ +class DateInvalidTimeZoneException extends Exception +{ +} + +/** + * @strict-properties + */ +class DateInvalidOperationException extends DateException +{ +} + +/** + * @strict-properties + */ +class DateMalformedStringException extends DateException +{ +} + +/** + * @strict-properties + */ +class DateMalformedIntervalStringException extends DateException +{ +} + +/** + * @strict-properties + */ +class DateMalformedPeriodStringException extends DateException +{ +} diff --git a/ext/date/php_date_arginfo.h b/ext/date/php_date_arginfo.h index f7920da2ce4b5..a16b6467aeafb 100644 --- a/ext/date/php_date_arginfo.h +++ b/ext/date/php_date_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 6949e2c795288f9615222b1fd496768ab20eb7c5 */ + * Stub hash: ce0bc9fd067a6598f66a65a9159674392e6cac4d */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_strtotime, 0, 1, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, datetime, IS_STRING, 0) @@ -549,6 +549,8 @@ ZEND_METHOD(DateTime, __wakeup); ZEND_METHOD(DateTime, __set_state); ZEND_METHOD(DateTime, createFromImmutable); ZEND_METHOD(DateTime, createFromInterface); +ZEND_METHOD(DateTime, modify); +ZEND_METHOD(DateTime, sub); ZEND_METHOD(DateTimeImmutable, __construct); ZEND_METHOD(DateTimeImmutable, __serialize); ZEND_METHOD(DateTimeImmutable, __unserialize); @@ -570,6 +572,7 @@ ZEND_METHOD(DateTimeZone, __unserialize); ZEND_METHOD(DateTimeZone, __wakeup); ZEND_METHOD(DateTimeZone, __set_state); ZEND_METHOD(DateInterval, __construct); +ZEND_METHOD(DateInterval, createFromDateString); ZEND_METHOD(DateInterval, __serialize); ZEND_METHOD(DateInterval, __unserialize); ZEND_METHOD(DateInterval, __wakeup); @@ -663,9 +666,9 @@ static const zend_function_entry class_DateTime_methods[] = { ZEND_ME_MAPPING(createFromFormat, date_create_from_format, arginfo_class_DateTime_createFromFormat, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME_MAPPING(getLastErrors, date_get_last_errors, arginfo_class_DateTime_getLastErrors, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME_MAPPING(format, date_format, arginfo_class_DateTime_format, ZEND_ACC_PUBLIC) - ZEND_ME_MAPPING(modify, date_modify, arginfo_class_DateTime_modify, ZEND_ACC_PUBLIC) + ZEND_ME(DateTime, modify, arginfo_class_DateTime_modify, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(add, date_add, arginfo_class_DateTime_add, ZEND_ACC_PUBLIC) - ZEND_ME_MAPPING(sub, date_sub, arginfo_class_DateTime_sub, ZEND_ACC_PUBLIC) + ZEND_ME(DateTime, sub, arginfo_class_DateTime_sub, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(getTimezone, date_timezone_get, arginfo_class_DateTime_getTimezone, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(setTimezone, date_timezone_set, arginfo_class_DateTime_setTimezone, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(getOffset, date_offset_get, arginfo_class_DateTime_getOffset, ZEND_ACC_PUBLIC) @@ -724,7 +727,7 @@ static const zend_function_entry class_DateTimeZone_methods[] = { static const zend_function_entry class_DateInterval_methods[] = { ZEND_ME(DateInterval, __construct, arginfo_class_DateInterval___construct, ZEND_ACC_PUBLIC) - ZEND_ME_MAPPING(createFromDateString, date_interval_create_from_date_string, arginfo_class_DateInterval_createFromDateString, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + ZEND_ME(DateInterval, createFromDateString, arginfo_class_DateInterval_createFromDateString, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME_MAPPING(format, date_interval_format, arginfo_class_DateInterval_format, ZEND_ACC_PUBLIC) ZEND_ME(DateInterval, __serialize, arginfo_class_DateInterval___serialize, ZEND_ACC_PUBLIC) ZEND_ME(DateInterval, __unserialize, arginfo_class_DateInterval___unserialize, ZEND_ACC_PUBLIC) @@ -748,6 +751,51 @@ static const zend_function_entry class_DatePeriod_methods[] = { ZEND_FE_END }; + +static const zend_function_entry class_DateError_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_DateObjectError_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_DateRangeError_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_DateException_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_DateInvalidTimeZoneException_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_DateInvalidOperationException_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_DateMalformedStringException_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_DateMalformedIntervalStringException_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_DateMalformedPeriodStringException_methods[] = { + ZEND_FE_END +}; + static void register_php_date_symbols(int module_number) { REGISTER_STRING_CONSTANT("DATE_ATOM", DATE_FORMAT_RFC3339, CONST_PERSISTENT); @@ -1083,3 +1131,102 @@ static zend_class_entry *register_class_DatePeriod(zend_class_entry *class_entry return class_entry; } + +static zend_class_entry *register_class_DateError(zend_class_entry *class_entry_Error) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DateError", class_DateError_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_Error); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_DateObjectError(zend_class_entry *class_entry_DateError) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DateObjectError", class_DateObjectError_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_DateError); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_DateRangeError(zend_class_entry *class_entry_DateRangeError) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DateRangeError", class_DateRangeError_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_DateRangeError); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_DateException(zend_class_entry *class_entry_Exception) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DateException", class_DateException_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_Exception); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_DateInvalidTimeZoneException(zend_class_entry *class_entry_Exception) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DateInvalidTimeZoneException", class_DateInvalidTimeZoneException_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_Exception); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_DateInvalidOperationException(zend_class_entry *class_entry_DateException) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DateInvalidOperationException", class_DateInvalidOperationException_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_DateException); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_DateMalformedStringException(zend_class_entry *class_entry_DateException) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DateMalformedStringException", class_DateMalformedStringException_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_DateException); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_DateMalformedIntervalStringException(zend_class_entry *class_entry_DateException) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DateMalformedIntervalStringException", class_DateMalformedIntervalStringException_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_DateException); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_DateMalformedPeriodStringException(zend_class_entry *class_entry_DateException) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DateMalformedPeriodStringException", class_DateMalformedPeriodStringException_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_DateException); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} diff --git a/ext/date/tests/68062.phpt b/ext/date/tests/68062.phpt index 66f7692cf4f30..15ec5fa81c1fc 100644 --- a/ext/date/tests/68062.phpt +++ b/ext/date/tests/68062.phpt @@ -10,9 +10,9 @@ echo $tz->getOffset($dt), "\n"; try { echo $tz->getOffset(1); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- 3600 -DateTimeZone::getOffset(): Argument #1 ($datetime) must be of type DateTimeInterface, int given +TypeError: DateTimeZone::getOffset(): Argument #1 ($datetime) must be of type DateTimeInterface, int given diff --git a/ext/date/tests/DateInterval_construct_exceptions.phpt b/ext/date/tests/DateInterval_construct_exceptions.phpt new file mode 100644 index 0000000000000..97df133adf088 --- /dev/null +++ b/ext/date/tests/DateInterval_construct_exceptions.phpt @@ -0,0 +1,21 @@ +--TEST-- +DateInterval constructor exceptions +--INI-- +date.timezone=Europe/London +--FILE-- +getMessage(), "\n"; + } +} + +check(fn() => new DateInterval("")); +check(fn() => new DateInterval("2007-05-11T15:30:00Z/")); +?> +--EXPECTF-- +DateMalformedIntervalStringException: Unknown or bad format () +DateMalformedIntervalStringException: Failed to parse interval (2007-05-11T15:30:00Z/) diff --git a/ext/date/tests/DateInterval_createFromDateString_broken.phpt b/ext/date/tests/DateInterval_createFromDateString_broken.phpt new file mode 100644 index 0000000000000..5b15fb154e8dc --- /dev/null +++ b/ext/date/tests/DateInterval_createFromDateString_broken.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test DateInterval::createFromDateString() function : nonsense data +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECTF-- +DateMalformedIntervalStringException: Unknown or bad format (foobar) at position 0 (f): The timezone could not be found in the database diff --git a/ext/date/tests/DateInterval_serialize-003.phpt b/ext/date/tests/DateInterval_serialize-003.phpt index b338a9ae93adb..cc1d9a371bb02 100644 --- a/ext/date/tests/DateInterval_serialize-003.phpt +++ b/ext/date/tests/DateInterval_serialize-003.phpt @@ -32,7 +32,11 @@ var_dump($d); echo "\n\nUsed serialised interval:\n"; $now = new DateTimeImmutable("2022-04-22 16:25:11 BST"); var_dump($now->add($e)); -var_dump($now->sub($e)); +try { + var_dump($now->sub($e)); +} catch (DateInvalidOperationException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} ?> --EXPECTF-- Original object: @@ -84,13 +88,4 @@ object(DateTimeImmutable)#4 (3) { ["timezone"]=> string(3) "BST" } - -Warning: DateTimeImmutable::sub(): Only non-special relative time specifications are supported for subtraction in %s on line %d -object(DateTimeImmutable)#4 (3) { - ["date"]=> - string(26) "2022-04-22 16:25:11.000000" - ["timezone_type"]=> - int(2) - ["timezone"]=> - string(3) "BST" -} +DateInvalidOperationException: DateTimeImmutable::sub(): Only non-special relative time specifications are supported for subtraction diff --git a/ext/date/tests/DateInterval_set_state_exception.phpt b/ext/date/tests/DateInterval_set_state_exception.phpt new file mode 100644 index 0000000000000..3a3c6c980b5d2 --- /dev/null +++ b/ext/date/tests/DateInterval_set_state_exception.phpt @@ -0,0 +1,22 @@ +--TEST-- +DateInterval invalid serialization data with date_string +--FILE-- + $propertySet ] ); + echo "OK\n"; + } catch (\Error $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; + } +} +?> +--EXPECT-- +OK +Error: Unknown or bad format (2023-01-16-foobar$*) at position 10 (-) while unserializing: Unexpected character diff --git a/ext/date/tests/DateInterval_uninitialised_exceptions.phpt b/ext/date/tests/DateInterval_uninitialised_exceptions.phpt new file mode 100644 index 0000000000000..7a7c296b7742d --- /dev/null +++ b/ext/date/tests/DateInterval_uninitialised_exceptions.phpt @@ -0,0 +1,30 @@ +--TEST-- +DateInterval uninitialised exceptions +--INI-- +date.timezone=Europe/London +--FILE-- +getMessage(), "\n"; + } +} + +$mdi = new MyDateInterval(); + +check(fn() => serialize($mdi)); +check(fn() => $mdi->format("Y-m-d")); +?> +--EXPECTF-- +DateObjectError: Object of type MyDateInterval (inheriting DateInterval) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateInterval (inheriting DateInterval) has not been correctly initialized by calling parent::__construct() in its constructor diff --git a/ext/date/tests/DatePeriod_by_ref_iterator.phpt b/ext/date/tests/DatePeriod_by_ref_iterator.phpt new file mode 100644 index 0000000000000..07e7fce39b4c8 --- /dev/null +++ b/ext/date/tests/DatePeriod_by_ref_iterator.phpt @@ -0,0 +1,22 @@ +--TEST-- +DatePeriod by-ref iterator +--FILE-- + new \DateTimeImmutable("2023-01-13 12:29:30"), 'end' => new \DateTimeImmutable("2023-01-16 16:49:29"), 'current' => new \DateTimeImmutable("2023-01-15 00:00:00"), + 'interval' => DateInterval::createFromDateString("tomorrow"), 'recurrences' => 1, 'include_start_date' => true, 'include_end_date' => true, +]; + +$d = DatePeriod::__set_state( $properties ); +try { + foreach( $d as &$item ) + { + echo $item->format(DateTime::ISO8601), "\n"; + } + echo "OK\n"; +} catch (\Error $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Error: An iterator cannot be used with foreach by reference diff --git a/ext/date/tests/DatePeriod_modify_readonly_property.phpt b/ext/date/tests/DatePeriod_modify_readonly_property.phpt new file mode 100644 index 0000000000000..e57c72339d8fd --- /dev/null +++ b/ext/date/tests/DatePeriod_modify_readonly_property.phpt @@ -0,0 +1,25 @@ +--TEST-- +DatePeriod modify readonly property +--FILE-- +interval = "foo"; +} catch( \Error $e ) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +try { + $foo =& $dp->interval; +} catch( \Error $e ) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} +?> +--EXPECTF-- +Error: Cannot modify readonly property DatePeriod::$interval +Error: Cannot modify readonly property DatePeriod::$interval diff --git a/ext/date/tests/DatePeriod_properties2.phpt b/ext/date/tests/DatePeriod_properties2.phpt index 376254698f9bb..1da4dcb9c2ff6 100644 --- a/ext/date/tests/DatePeriod_properties2.phpt +++ b/ext/date/tests/DatePeriod_properties2.phpt @@ -20,33 +20,33 @@ foreach ($properties as $property) { try { $period->$property = "new"; } catch (Error $e) { - echo $e->getMessage() . "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { $period->$property[] = "extra"; } catch (Error $e) { - echo $e->getMessage() . "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } } try { $period->start->modify("+1 hour"); } catch (Error $e) { - echo $e->getMessage() . "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -Cannot modify readonly property DatePeriod::$recurrences -Cannot modify readonly property DatePeriod::$recurrences -Cannot modify readonly property DatePeriod::$include_start_date -Cannot modify readonly property DatePeriod::$include_start_date -Cannot modify readonly property DatePeriod::$start -Cannot modify readonly property DatePeriod::$start -Cannot modify readonly property DatePeriod::$current -Cannot modify readonly property DatePeriod::$current -Cannot modify readonly property DatePeriod::$end -Cannot modify readonly property DatePeriod::$end -Cannot modify readonly property DatePeriod::$interval -Cannot modify readonly property DatePeriod::$interval +Error: Cannot modify readonly property DatePeriod::$recurrences +Error: Cannot modify readonly property DatePeriod::$recurrences +Error: Cannot modify readonly property DatePeriod::$include_start_date +Error: Cannot modify readonly property DatePeriod::$include_start_date +Error: Cannot modify readonly property DatePeriod::$start +Error: Cannot modify readonly property DatePeriod::$start +Error: Cannot modify readonly property DatePeriod::$current +Error: Cannot modify readonly property DatePeriod::$current +Error: Cannot modify readonly property DatePeriod::$end +Error: Cannot modify readonly property DatePeriod::$end +Error: Cannot modify readonly property DatePeriod::$interval +Error: Cannot modify readonly property DatePeriod::$interval diff --git a/ext/date/tests/DatePeriod_set_state_exception.phpt b/ext/date/tests/DatePeriod_set_state_exception.phpt new file mode 100644 index 0000000000000..07fd322ba2d7f --- /dev/null +++ b/ext/date/tests/DatePeriod_set_state_exception.phpt @@ -0,0 +1,65 @@ +--TEST-- +DatePeriod invalid serialization data +--FILE-- + new \DateTimeImmutable("2023-01-13 12:29:30"), 'end' => new \DateTimeImmutable("2023-01-16 16:49:29"), 'current' => new \DateTimeImmutable("2023-01-15 00:00:00"), + 'interval' => DateInterval::createFromDateString("tomorrow"), 'recurrences' => 1, 'include_start_date' => true, 'include_end_date' => true, + ], + [ + 'start' => null, 'end' => null, 'current' => null, + 'interval' => DateInterval::createFromDateString("tomorrow"), 'recurrences' => 1, 'include_start_date' => false, 'include_end_date' => false, + ], + /* Error situations */ + [ + 'start' => "2023-01-13 12:29:30", 'end' => new \DateTimeImmutable("2023-01-16 16:49:29"), 'current' => new \DateTimeImmutable("2023-01-15 00:00:00"), + 'interval' => DateInterval::createFromDateString("tomorrow"), 'recurrences' => 1, 'include_start_date' => true, 'include_end_date' => true, + ], + [ + 'start' => new \DateTimeImmutable("2023-01-13 12:29:30"), 'end' => "2023-01-16 16:49:29", 'current' => new \DateTimeImmutable("2023-01-15 00:00:00"), + 'interval' => DateInterval::createFromDateString("tomorrow"), 'recurrences' => 1, 'include_start_date' => true, 'include_end_date' => true, + ], + [ + 'start' => new \DateTimeImmutable("2023-01-13 12:29:30"), 'end' => new \DateTimeImmutable("2023-01-16 16:49:29"), 'current' => "2023-01-15 00:00:00", + 'interval' => DateInterval::createFromDateString("tomorrow"), 'recurrences' => 1, 'include_start_date' => true, 'include_end_date' => true, + ], + [ + 'start' => new \DateTimeImmutable("2023-01-13 12:29:30"), 'end' => new \DateTimeImmutable("2023-01-16 16:49:29"), 'current' => new \DateTimeImmutable("2023-01-15 00:00:00"), + 'interval' => "tomorrow", 'recurrences' => 1, 'include_start_date' => true, 'include_end_date' => true, + ], + [ + 'start' => new \DateTimeImmutable("2023-01-13 12:29:30"), 'end' => new \DateTimeImmutable("2023-01-16 16:49:29"), 'current' => new \DateTimeImmutable("2023-01-15 00:00:00"), + 'interval' => DateInterval::createFromDateString("tomorrow"), 'recurrences' => -1, 'include_start_date' => true, 'include_end_date' => true, + ], + [ + 'start' => new \DateTimeImmutable("2023-01-13 12:29:30"), 'end' => new \DateTimeImmutable("2023-01-16 16:49:29"), 'current' => new \DateTimeImmutable("2023-01-15 00:00:00"), + 'interval' => DateInterval::createFromDateString("tomorrow"), 'recurrences' => 1, 'include_start_date' => "true", 'include_end_date' => true, + ], + [ + 'start' => new \DateTimeImmutable("2023-01-13 12:29:30"), 'end' => new \DateTimeImmutable("2023-01-16 16:49:29"), 'current' => new \DateTimeImmutable("2023-01-15 00:00:00"), + 'interval' => DateInterval::createFromDateString("tomorrow"), 'recurrences' => 1, 'include_start_date' => true, 'include_end_date' => "true", + ], +]; + +foreach( $propertySets as $propertySet ) +{ + try { + $d = DatePeriod::__set_state( $propertySet ); + echo "OK\n"; + } catch (\Error $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; + } +} +?> +--EXPECT-- +OK +OK +Error: Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object diff --git a/ext/date/tests/DatePeriod_uninitialised_exceptions.phpt b/ext/date/tests/DatePeriod_uninitialised_exceptions.phpt new file mode 100644 index 0000000000000..753bb0fa68c4a --- /dev/null +++ b/ext/date/tests/DatePeriod_uninitialised_exceptions.phpt @@ -0,0 +1,45 @@ +--TEST-- +DateTime uninitialised exceptions +--INI-- +date.timezone=Europe/London +--FILE-- +getMessage(), "\n"; + } +} + +$mdp = new MyDatePeriod(); + +check(fn() => serialize($mdp)); +check(fn() => $mdp->getStartDate()); +check(fn() => $mdp->getDateInterval()); + +check(function() use ($mdp) { + foreach($mdp as $foo) + { + } +}); + +/* Allowed to be empty */ +check(fn() => $mdp->getEndDate()); +check(fn() => $mdp->getRecurrences()); +?> +--EXPECTF-- +DateObjectError: Object of type MyDatePeriod (inheriting DatePeriod) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDatePeriod (inheriting DatePeriod) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDatePeriod (inheriting DatePeriod) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type DatePeriod has not been correctly initialized by calling parent::__construct() in its constructor +NULL +NULL diff --git a/ext/date/tests/DatePeriod_wrong_arguments.phpt b/ext/date/tests/DatePeriod_wrong_arguments.phpt new file mode 100644 index 0000000000000..0f33f5261a648 --- /dev/null +++ b/ext/date/tests/DatePeriod_wrong_arguments.phpt @@ -0,0 +1,25 @@ +--TEST-- +DatePeriod arguments/wrong arguments +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECT-- +OK +OK +OK +TypeError: DatePeriod::__construct() accepts (DateTimeInterface, DateInterval, int [, int]), or (DateTimeInterface, DateInterval, DateTime [, int]), or (string [, int]) as arguments diff --git a/ext/date/tests/DateTimeImmutable_createFromInterface_exceptions.phpt b/ext/date/tests/DateTimeImmutable_createFromInterface_exceptions.phpt new file mode 100644 index 0000000000000..e3c2c4d33b735 --- /dev/null +++ b/ext/date/tests/DateTimeImmutable_createFromInterface_exceptions.phpt @@ -0,0 +1,37 @@ +--TEST-- +DateTimeImmutable::createFromInterface exception +--INI-- +date.timezone=Europe/London +--FILE-- +getMessage(), "\n"; +} + +$i = new MyDateTimeImmutable(); +try { + $m = DateTimeImmutable::createFromInterface( $i ); +} catch (\DateObjectError $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} +?> +--EXPECTF-- +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor diff --git a/ext/date/tests/DateTimeImmutable_createFromMutable-001.phpt b/ext/date/tests/DateTimeImmutable_createFromMutable-001.phpt index 4f542c82c8009..a6ebaa82404b6 100644 --- a/ext/date/tests/DateTimeImmutable_createFromMutable-001.phpt +++ b/ext/date/tests/DateTimeImmutable_createFromMutable-001.phpt @@ -12,7 +12,7 @@ var_dump( $i ); try { DateTimeImmutable::createFromMutable( date_create_immutable( $current ) ); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECTF-- @@ -24,4 +24,4 @@ object(DateTimeImmutable)#%d (3) { ["timezone"]=> string(13) "Europe/London" } -DateTimeImmutable::createFromMutable(): Argument #1 ($object) must be of type DateTime, DateTimeImmutable given +TypeError: DateTimeImmutable::createFromMutable(): Argument #1 ($object) must be of type DateTime, DateTimeImmutable given diff --git a/ext/date/tests/DateTimeImmutable_createFromMutable-002.phpt b/ext/date/tests/DateTimeImmutable_createFromMutable-002.phpt index ccbbe33f1786c..78d87f1e898ce 100644 --- a/ext/date/tests/DateTimeImmutable_createFromMutable-002.phpt +++ b/ext/date/tests/DateTimeImmutable_createFromMutable-002.phpt @@ -14,7 +14,7 @@ var_dump( $i ); try { MyDateTimeImmutable::createFromMutable( date_create_immutable( $current ) ); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECTF-- @@ -26,4 +26,4 @@ object(MyDateTimeImmutable)#%d (3) { ["timezone"]=> string(13) "Europe/London" } -DateTimeImmutable::createFromMutable(): Argument #1 ($object) must be of type DateTime, DateTimeImmutable given +TypeError: DateTimeImmutable::createFromMutable(): Argument #1 ($object) must be of type DateTime, DateTimeImmutable given diff --git a/ext/date/tests/DateTimeImmutable_createFromMutable_exceptions.phpt b/ext/date/tests/DateTimeImmutable_createFromMutable_exceptions.phpt new file mode 100644 index 0000000000000..2d311ad138eb6 --- /dev/null +++ b/ext/date/tests/DateTimeImmutable_createFromMutable_exceptions.phpt @@ -0,0 +1,23 @@ +--TEST-- +DateTimeImmutable::createFromMutable exception +--INI-- +date.timezone=Europe/London +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECTF-- +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor diff --git a/ext/date/tests/DateTimeImmutable_modify_invalid_format.phpt b/ext/date/tests/DateTimeImmutable_modify_invalid_format.phpt index 3386f725acffa..8f4d5891da666 100644 --- a/ext/date/tests/DateTimeImmutable_modify_invalid_format.phpt +++ b/ext/date/tests/DateTimeImmutable_modify_invalid_format.phpt @@ -4,9 +4,12 @@ DateTimeImmutable::modify() with invalid format modify('')); +try { + var_dump($datetime->modify('')); +} catch (DateMalformedStringException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} ?> --EXPECTF-- -Warning: DateTimeImmutable::modify(): Failed to parse time string () at position 0 ( in %s on line %d -bool(false) +DateMalformedStringException: DateTimeImmutable::modify(): Failed to parse time string () at position 0 ( ): Empty string diff --git a/ext/date/tests/DateTimeImmutable_set_state_exception.phpt b/ext/date/tests/DateTimeImmutable_set_state_exception.phpt new file mode 100644 index 0000000000000..6f42c6a81fa2b --- /dev/null +++ b/ext/date/tests/DateTimeImmutable_set_state_exception.phpt @@ -0,0 +1,38 @@ +--TEST-- +DateTimeImmutable invalid serialization data +--FILE-- + "2023-01-13 12:29:30", 'timezone_type' => 1, 'timezone' => "+02:30" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 3, 'timezone' => "Europe/Kyiv" ], + [ 'date' => 2023.113, 'timezone_type' => 1, 'timezone' => "+02:30" ], + [ 'date' => 2023.113, 'timezone_type' => 3, 'timezone' => "Europe/Kyiv" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 1.4, 'timezone' => "+02:30" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 3.4, 'timezone' => "Europe/Kyiv" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 1, 'timezone' => 2.5 ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 3, 'timezone' => 2.5 ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 3, 'timezone' => "Europe/Lviv" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 4, 'timezone' => "Europe/Kyiv" ], +]; + +foreach( $propertySets as $propertySet ) +{ + try { + $d = DateTimeImmutable::__set_state( $propertySet ); + echo "OK\n"; + } catch (\Error $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; + } +} +?> +--EXPECT-- +OK +OK +Error: Invalid serialization data for DateTimeImmutable object +Error: Invalid serialization data for DateTimeImmutable object +Error: Invalid serialization data for DateTimeImmutable object +Error: Invalid serialization data for DateTimeImmutable object +Error: Invalid serialization data for DateTimeImmutable object +Error: Invalid serialization data for DateTimeImmutable object +Error: Invalid serialization data for DateTimeImmutable object +Error: Invalid serialization data for DateTimeImmutable object diff --git a/ext/date/tests/DateTimeImmutable_uninitialised_exceptions.phpt b/ext/date/tests/DateTimeImmutable_uninitialised_exceptions.phpt new file mode 100644 index 0000000000000..38aed67b42c30 --- /dev/null +++ b/ext/date/tests/DateTimeImmutable_uninitialised_exceptions.phpt @@ -0,0 +1,79 @@ +--TEST-- +DateTime uninitialised exceptions +--INI-- +date.timezone=Europe/London +--FILE-- +getMessage(), "\n"; + } +} + +$mdti = new MyDateTimeImmutable(); +$dt = new DateTimeImmutable(); +$di = DateInterval::createFromDateString("tomorrow"); +$dtz = new DateTimeZone("Europe/Kyiv"); + +check(fn() => DateTimeImmutable::createFromInterface($mdti)); +check(fn() => DateTime::createFromImmutable($mdti)); +check(fn() => serialize($mdti)); +check(fn() => date_format($mdti, DateTime::ISO8601)); +check(fn() => $mdti->format(DateTime::ISO8601)); +check(fn() => $mdti->modify("+1 day")); +check(fn() => $mdti->add($di)); +check(fn() => $mdti->sub($di)); +check(fn() => date_timezone_get($mdti)); +check(fn() => $mdti->getTimeZone()); +check(fn() => $mdti->setTimeZone($dtz)); +check(fn() => date_offset_get($mdti)); +check(fn() => $mdti->getOffset()); +check(fn() => $mdti->setTime(17, 59, 53)); +check(fn() => $mdti->setDate(2023, 1, 16)); +check(fn() => $mdti->setISODate(2023, 3, 1)); +check(fn() => $mdti->setTimestamp(time())); +check(fn() => date_timestamp_get($mdti)); +check(fn() => $mdti->getTimestamp()); +check(fn() => date_diff($dt, $mdti)); +check(fn() => date_diff($mdti, $dt)); +check(fn() => date_diff($mdti, $mdti)); +check(fn() => $dt->diff($mdti)); +check(fn() => $mdti->diff($dt)); +check(fn() => $mdti->diff($mdti)); +?> +--EXPECTF-- +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor diff --git a/ext/date/tests/DateTimeZone_compare.phpt b/ext/date/tests/DateTimeZone_compare.phpt new file mode 100644 index 0000000000000..c187be332cf56 --- /dev/null +++ b/ext/date/tests/DateTimeZone_compare.phpt @@ -0,0 +1,46 @@ +--TEST-- +DateTimeZone compare handler +--FILE-- +getMessage(), "\n"; +} + +try { + var_dump($dtzID < $mdtz); +} catch (\DateObjectError $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +try { + var_dump($dtzID < $dtzAbbr); +} catch (\DateException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +try { + var_dump($dtzAbbr < $dtzUTC); +} catch (\DateException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} +?> +--EXPECT-- +DateObjectError: Trying to compare uninitialized DateTimeZone objects +DateObjectError: Trying to compare uninitialized DateTimeZone objects +DateException: Cannot compare two different kinds of DateTimeZone objects +DateException: Cannot compare two different kinds of DateTimeZone objects diff --git a/ext/date/tests/DateTimeZone_compare_basic1.phpt b/ext/date/tests/DateTimeZone_compare_basic1.phpt index 27cd7e8208702..a45485a1a7b75 100644 --- a/ext/date/tests/DateTimeZone_compare_basic1.phpt +++ b/ext/date/tests/DateTimeZone_compare_basic1.phpt @@ -14,7 +14,11 @@ foreach ($timezones as [$timezone1, $timezone2]) { compare_timezones($timezone1, $timezone2); } -var_dump(new DateTimeZone('Europe/Berlin') == new DateTimeZone('CET')); +try { + var_dump(new DateTimeZone('Europe/Berlin') == new DateTimeZone('CET')); +} catch (DateException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} function compare_timezones($timezone1, $timezone2) { @@ -41,7 +45,7 @@ $tz2 = new MyDateTimeZone(); try { var_dump($tz1 == $tz2); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> @@ -70,7 +74,5 @@ compare Europe/Amsterdam with Europe/Berlin < bool(false) = bool(false) > bool(false) - -Warning: main(): Trying to compare different kinds of DateTimeZone objects in %s on line %d -bool(false) -Trying to compare uninitialized DateTimeZone objects +DateException: Cannot compare two different kinds of DateTimeZone objects +DateObjectError: Trying to compare uninitialized DateTimeZone objects diff --git a/ext/date/tests/DateTimeZone_construct_error.phpt b/ext/date/tests/DateTimeZone_construct_error.phpt index dd0b1bb70893e..6a48231c8dc96 100644 --- a/ext/date/tests/DateTimeZone_construct_error.phpt +++ b/ext/date/tests/DateTimeZone_construct_error.phpt @@ -1,9 +1,9 @@ --TEST-- -Test new DateTimeZone() : error conditions +Test new DateTimeZone(): Too few arguments --FILE-- getMessage(), "\n"; +} catch (ArgumentCountError $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> @@ -21,4 +21,4 @@ try { *** Testing DateTimeZone() : error conditions *** -- Testing new DateTimeZone() with more than expected no. of arguments -- -DateTimeZone::__construct() expects exactly 1 argument, 2 given +ArgumentCountError: DateTimeZone::__construct() expects exactly 1 argument, 2 given diff --git a/ext/date/tests/DateTimeZone_serialize_errors.phpt b/ext/date/tests/DateTimeZone_serialize_errors.phpt index f89e3bfafcbf4..866624e5f520d 100644 --- a/ext/date/tests/DateTimeZone_serialize_errors.phpt +++ b/ext/date/tests/DateTimeZone_serialize_errors.phpt @@ -7,9 +7,8 @@ $serialized = 'O:12:"DateTimeZone":2:{s:13:"timezone_type";i:3;s:8:"timezone";s: try { $tz = unserialize($serialized); } catch (Throwable $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> ---EXPECTF-- -Warning: DateTimeZone::__unserialize(): Timezone must not contain null bytes in %s on line %d -Invalid serialization data for DateTimeZone object +--EXPECT-- +Error: Invalid serialization data for DateTimeZone object diff --git a/ext/date/tests/DateTimeZone_set_state_exception.phpt b/ext/date/tests/DateTimeZone_set_state_exception.phpt new file mode 100644 index 0000000000000..68eb50a2fd6bd --- /dev/null +++ b/ext/date/tests/DateTimeZone_set_state_exception.phpt @@ -0,0 +1,38 @@ +--TEST-- +DateTimeZone invalid serialization data +--FILE-- + 1, 'timezone' => "+02:30" ], + [ 'timezone_type' => 3, 'timezone' => "Europe/Kyiv" ], + [ 'timezone_type' => 1.4, 'timezone' => "+02:30" ], + [ 'timezone_type' => 3.4, 'timezone' => "Europe/Kyiv" ], + [ 'timezone_type' => 1, 'timezone' => 2.5 ], + [ 'timezone_type' => 3, 'timezone' => 2.5 ], + [ 'timezone_type' => 3, 'timezone' => "Europe/K\0v" ], + [ 'timezone_type' => 3, 'timezone' => "99:99:99" ], + [ 'timezone_type' => 3, 'timezone' => "Europe/Lviv" ], + [ 'timezone_type' => 4, 'timezone' => "Europe/Kyiv" ], +]; + +foreach( $propertySets as $propertySet ) +{ + try { + $d = DateTimeZone::__set_state( $propertySet ); + echo "OK\n"; + } catch (\Error $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; + } +} +?> +--EXPECT-- +OK +OK +Error: Invalid serialization data for DateTimeZone object +Error: Invalid serialization data for DateTimeZone object +Error: Invalid serialization data for DateTimeZone object +Error: Invalid serialization data for DateTimeZone object +Error: Invalid serialization data for DateTimeZone object +Error: Invalid serialization data for DateTimeZone object +Error: Invalid serialization data for DateTimeZone object +Error: Invalid serialization data for DateTimeZone object diff --git a/ext/date/tests/DateTimeZone_uninitialised_exceptions.phpt b/ext/date/tests/DateTimeZone_uninitialised_exceptions.phpt new file mode 100644 index 0000000000000..ce036e306315c --- /dev/null +++ b/ext/date/tests/DateTimeZone_uninitialised_exceptions.phpt @@ -0,0 +1,58 @@ +--TEST-- +DateTime uninitialised exceptions +--INI-- +date.timezone=Europe/London +--FILE-- +getMessage(), "\n"; + } +} + +$mdt = new MyDateTime(); +$mdtz = new MyDateTimeZone(); +$dtz = new DateTimeZone("Europe/Kyiv"); +$dt = new DateTime("2023-01-16 18:18"); + +check(fn() => serialize($mdtz)); +check(fn() => timezone_name_get($mdtz)); +check(fn() => $mdtz->getName()); +check(fn() => timezone_offset_get($mdtz, $dt)); +check(fn() => $mdtz->getOffset($dt)); +check(fn() => timezone_offset_get($dtz, $mdt)); +check(fn() => $dtz->getOffset($mdt)); +check(fn() => timezone_transitions_get($mdtz, time())); +check(fn() => $mdtz->getTransitions(time())); +check(fn() => timezone_location_get($mdtz,)); +check(fn() => $mdtz->getLocation()); +?> +--EXPECTF-- +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor diff --git a/ext/date/tests/DateTime_compare.phpt b/ext/date/tests/DateTime_compare.phpt new file mode 100644 index 0000000000000..9f712f121e433 --- /dev/null +++ b/ext/date/tests/DateTime_compare.phpt @@ -0,0 +1,48 @@ +--TEST-- +DateTime/DateTimeImmutable compare handler +--FILE-- +getMessage(), "\n"; +} + +try { + var_dump($MDT < $DT); +} catch (\DateObjectError $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +try { + var_dump($DTI < $MDT); +} catch (\DateObjectError $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +try { + var_dump($MDT < $DTI); +} catch (\DateObjectError $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} +?> +--EXPECT-- +bool(false) +DateObjectError: Trying to compare an incomplete DateTime or DateTimeImmutable object +DateObjectError: Trying to compare an incomplete DateTime or DateTimeImmutable object +DateObjectError: Trying to compare an incomplete DateTime or DateTimeImmutable object +DateObjectError: Trying to compare an incomplete DateTime or DateTimeImmutable object diff --git a/ext/date/tests/DateTime_construct_error.phpt b/ext/date/tests/DateTime_construct_error.phpt index 56ab1f3003ff5..e1a99ed7b3ddb 100644 --- a/ext/date/tests/DateTime_construct_error.phpt +++ b/ext/date/tests/DateTime_construct_error.phpt @@ -1,9 +1,9 @@ --TEST-- -Test new DateTime() : error conditions +Test new DateTime(): error conditions --FILE-- getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> @@ -22,4 +22,4 @@ try { *** Testing date_create() : error conditions *** -- Testing new DateTime() with more than expected no. of arguments -- -DateTime::__construct() expects at most 2 arguments, 3 given +ArgumentCountError: DateTime::__construct() expects at most 2 arguments, 3 given diff --git a/ext/date/tests/DateTime_createFromImmutable-001.phpt b/ext/date/tests/DateTime_createFromImmutable-001.phpt index 031c8764847a4..e29a5f32341a7 100644 --- a/ext/date/tests/DateTime_createFromImmutable-001.phpt +++ b/ext/date/tests/DateTime_createFromImmutable-001.phpt @@ -17,7 +17,7 @@ var_dump( $i->format('Y-m-d H:i:s') === $current ); try { DateTime::createFromImmutable( date_create( $current ) ); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECTF-- @@ -30,4 +30,4 @@ object(DateTime)#%d (3) { string(13) "Europe/London" } bool(true) -DateTime::createFromImmutable(): Argument #1 ($object) must be of type DateTimeImmutable, DateTime given +TypeError: DateTime::createFromImmutable(): Argument #1 ($object) must be of type DateTimeImmutable, DateTime given diff --git a/ext/date/tests/DateTime_createFromImmutable-002.phpt b/ext/date/tests/DateTime_createFromImmutable-002.phpt index 5b8c3a5a7cfe6..778e2a98af447 100644 --- a/ext/date/tests/DateTime_createFromImmutable-002.phpt +++ b/ext/date/tests/DateTime_createFromImmutable-002.phpt @@ -19,7 +19,7 @@ var_dump( $i->format('Y-m-d H:i:s') === $current ); try { MyDateTime::createFromImmutable( date_create( $current ) ); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECTF-- @@ -32,4 +32,4 @@ object(MyDateTime)#%d (3) { string(13) "Europe/London" } bool(true) -DateTime::createFromImmutable(): Argument #1 ($object) must be of type DateTimeImmutable, DateTime given +TypeError: DateTime::createFromImmutable(): Argument #1 ($object) must be of type DateTimeImmutable, DateTime given diff --git a/ext/date/tests/DateTime_modify_invalid_format.phpt b/ext/date/tests/DateTime_modify_invalid_format.phpt new file mode 100644 index 0000000000000..1e1a1721c4bca --- /dev/null +++ b/ext/date/tests/DateTime_modify_invalid_format.phpt @@ -0,0 +1,18 @@ +--TEST-- +DateTime::modify() with empty string as format +--FILE-- +modify('')); +} catch (DateMalformedStringException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +?> +--EXPECTF-- +Warning: date_modify(): Failed to parse time string () at position 0 ( ): Empty string in %s +bool(false) +DateMalformedStringException: DateTime::modify(): Failed to parse time string () at position 0 ( ): Empty string diff --git a/ext/date/tests/DateTime_set_state_exception.phpt b/ext/date/tests/DateTime_set_state_exception.phpt new file mode 100644 index 0000000000000..8b16ec7011b62 --- /dev/null +++ b/ext/date/tests/DateTime_set_state_exception.phpt @@ -0,0 +1,40 @@ +--TEST-- +DateTime invalid serialization data +--FILE-- + "2023-01-13 12:29:30", 'timezone_type' => 1, 'timezone' => "+02:30" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 3, 'timezone' => "Europe/Kyiv" ], + /* Error situations */ + [ 'date' => 2023.113, 'timezone_type' => 1, 'timezone' => "+02:30" ], + [ 'date' => 2023.113, 'timezone_type' => 3, 'timezone' => "Europe/Kyiv" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 1.4, 'timezone' => "+02:30" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 3.4, 'timezone' => "Europe/Kyiv" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 1, 'timezone' => 2.5 ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 3, 'timezone' => 2.5 ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 3, 'timezone' => "Europe/Lviv" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 4, 'timezone' => "Europe/Kyiv" ], +]; + +foreach( $propertySets as $propertySet ) +{ + try { + $d = DateTime::__set_state( $propertySet ); + echo "OK\n"; + } catch (\Error $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; + } +} +?> +--EXPECT-- +OK +OK +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object diff --git a/ext/date/tests/DateTime_uninitialised_exceptions.phpt b/ext/date/tests/DateTime_uninitialised_exceptions.phpt new file mode 100644 index 0000000000000..1680fedb7e0bf --- /dev/null +++ b/ext/date/tests/DateTime_uninitialised_exceptions.phpt @@ -0,0 +1,91 @@ +--TEST-- +DateTime uninitialised exceptions +--INI-- +date.timezone=Europe/London +--FILE-- +getMessage(), "\n"; + } +} + +$mdt = new MyDateTime(); +$dt = new DateTime(); +$di = DateInterval::createFromDateString("tomorrow"); +$dtz = new DateTimeZone("Europe/Kyiv"); + +check(fn() => DateTime::createFromInterface($mdt)); +check(fn() => DateTimeImmutable::createFromMutable($mdt)); +check(fn() => serialize($mdt)); +check(fn() => date_format($mdt, DateTime::ISO8601)); +check(fn() => $mdt->format(DateTime::ISO8601)); +check(fn() => date_modify($mdt, "+1 day")); +check(fn() => $mdt->modify("+1 day")); +check(fn() => $mdt->add($di)); +check(fn() => $mdt->sub($di)); +check(fn() => date_timezone_get($mdt)); +check(fn() => $mdt->getTimeZone()); +check(fn() => date_timezone_set($mdt, $dtz)); +check(fn() => $mdt->setTimeZone($dtz)); +check(fn() => date_offset_get($mdt)); +check(fn() => $mdt->getOffset()); +check(fn() => date_time_set($mdt, 17, 59, 53)); +check(fn() => $mdt->setTime(17, 59, 53)); +check(fn() => date_date_set($mdt, 2023, 1, 16)); +check(fn() => $mdt->setDate(2023, 1, 16)); +check(fn() => date_isodate_set($mdt, 2023, 3, 1)); +check(fn() => $mdt->setISODate(2023, 3, 1)); +check(fn() => date_timestamp_set($mdt, time())); +check(fn() => $mdt->setTimestamp(time())); +check(fn() => date_timestamp_get($mdt)); +check(fn() => $mdt->getTimestamp()); +check(fn() => date_diff($dt, $mdt)); +check(fn() => date_diff($mdt, $dt)); +check(fn() => date_diff($mdt, $mdt)); +check(fn() => $dt->diff($mdt)); +check(fn() => $mdt->diff($dt)); +check(fn() => $mdt->diff($mdt)); +?> +--EXPECTF-- +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor diff --git a/ext/date/tests/DateTime_wakeup_exception.phpt b/ext/date/tests/DateTime_wakeup_exception.phpt new file mode 100644 index 0000000000000..dd51e52a9b1e3 --- /dev/null +++ b/ext/date/tests/DateTime_wakeup_exception.phpt @@ -0,0 +1,34 @@ +--TEST-- +DateTime invalid serialization data (wakeup) +--FILE-- +getMessage(), "\n"; + } +} +?> +--EXPECTF-- +OK? object +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object +OK? object + +Warning: unserialize(): Error at offset 109 of 122 bytes in %sDateTime_wakeup_exception.php on line 15 +OK? boolean diff --git a/ext/date/tests/bug-gh8471.phpt b/ext/date/tests/bug-gh8471.phpt index 6857551008e08..2f6656849f6c8 100644 --- a/ext/date/tests/bug-gh8471.phpt +++ b/ext/date/tests/bug-gh8471.phpt @@ -44,7 +44,7 @@ try { ?> --EXPECTF-- -The DateTime object has not been correctly initialized by its constructor -The DateTimeInterface object has not been correctly initialized by its constructor -The DateTimeImmutable object has not been correctly initialized by its constructor -The DateTimeInterface object has not been correctly initialized by its constructor +Object of type DateTime has not been correctly initialized by calling parent::__construct() in its constructor +Object of type DateTime has not been correctly initialized by calling parent::__construct() in its constructor +Object of type DateTimeImmutable has not been correctly initialized by calling parent::__construct() in its constructor +Object of type DateTimeImmutable has not been correctly initialized by calling parent::__construct() in its constructor diff --git a/ext/date/tests/bug-gh9763.phpt b/ext/date/tests/bug-gh9763.phpt index dd7b0fb0e48e4..7166c7d27e823 100644 --- a/ext/date/tests/bug-gh9763.phpt +++ b/ext/date/tests/bug-gh9763.phpt @@ -11,18 +11,18 @@ foreach ( [ '+99:60', '+99:62', '-99:62', '-99:60', '+9960', '-9960', '+9959', ' $d = new DateTimeZone($test); echo $d->getName(), "\n"; } catch (Exception $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } } ?> --EXPECT-- -Testing +99:60: DateTimeZone::__construct(): Timezone offset is out of range (+99:60) -Testing +99:62: DateTimeZone::__construct(): Timezone offset is out of range (+99:62) -Testing -99:62: DateTimeZone::__construct(): Timezone offset is out of range (-99:62) -Testing -99:60: DateTimeZone::__construct(): Timezone offset is out of range (-99:60) -Testing +9960: DateTimeZone::__construct(): Timezone offset is out of range (+9960) -Testing -9960: DateTimeZone::__construct(): Timezone offset is out of range (-9960) +Testing +99:60: DateInvalidTimeZoneException: DateTimeZone::__construct(): Timezone offset is out of range (+99:60) +Testing +99:62: DateInvalidTimeZoneException: DateTimeZone::__construct(): Timezone offset is out of range (+99:62) +Testing -99:62: DateInvalidTimeZoneException: DateTimeZone::__construct(): Timezone offset is out of range (-99:62) +Testing -99:60: DateInvalidTimeZoneException: DateTimeZone::__construct(): Timezone offset is out of range (-99:60) +Testing +9960: DateInvalidTimeZoneException: DateTimeZone::__construct(): Timezone offset is out of range (+9960) +Testing -9960: DateInvalidTimeZoneException: DateTimeZone::__construct(): Timezone offset is out of range (-9960) Testing +9959: +99:59 Testing -9959: -99:59 diff --git a/ext/date/tests/bug36988.phpt b/ext/date/tests/bug36988.phpt index 32359808517b1..4898ef68d0388 100644 --- a/ext/date/tests/bug36988.phpt +++ b/ext/date/tests/bug36988.phpt @@ -9,8 +9,8 @@ $start = microtime(true); try { $a = mktime(1, 1, 1, 1, 1, 11111111111); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -mktime(): Argument #6 ($year) must be of type ?int, float given +TypeError: mktime(): Argument #6 ($year) must be of type ?int, float given diff --git a/ext/date/tests/bug44562.phpt b/ext/date/tests/bug44562.phpt index 0448e95ec341a..2517207b367a4 100644 --- a/ext/date/tests/bug44562.phpt +++ b/ext/date/tests/bug44562.phpt @@ -7,7 +7,7 @@ date_default_timezone_set('Europe/Oslo'); try { $dp = new DatePeriod('2D'); } catch (Exception $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } $begin = new DateTime( "2008-07-20T22:44:53+0200" ); @@ -21,7 +21,7 @@ foreach ( $dp as $d ) ?> --EXPECT-- -Unknown or bad format (2D) +DateMalformedPeriodStringException: Unknown or bad format (2D) string(24) "2008-07-20T22:44:53+0200" string(24) "2008-07-21T22:44:53+0200" string(24) "2008-07-22T22:44:53+0200" diff --git a/ext/date/tests/bug45866.phpt b/ext/date/tests/bug45866.phpt index f4b09b6daf7c9..0e062ffc397c6 100644 --- a/ext/date/tests/bug45866.phpt +++ b/ext/date/tests/bug45866.phpt @@ -13,12 +13,15 @@ $date->modify( "61538461538 day" ); echo $date->format( 'r' ), "\n"; $date = new DateTime( '2009-07-29 16:44:23 Europe/London' ); -$date->modify( "£61538461538 day" ); +try { + $date->modify( "£61538461538 day" ); +} catch (DateMalformedStringException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} echo $date->format( 'r' ), "\n"; ?> --EXPECTF-- Thu, 14 Aug 168488594 16:44:23 +0100 Thu, 14 Aug 168488594 16:44:23 +0100 - -Warning: DateTime::modify(): Failed to parse time string (£61538461538 day) at position 0 (%s): Unexpected character in %sbug45866.php on line 11 +DateMalformedStringException: DateTime::modify(): Failed to parse time string (£61538461538 day) at position 0 (%s): Unexpected character Wed, 29 Jul 2009 16:44:23 +0100 diff --git a/ext/date/tests/bug48476.phpt b/ext/date/tests/bug48476.phpt index 139c2e17e2bac..4b219e541e856 100644 --- a/ext/date/tests/bug48476.phpt +++ b/ext/date/tests/bug48476.phpt @@ -13,14 +13,14 @@ $o = new MyDateTime; try { var_dump($o->format("d")); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } $x = clone $o; try { var_dump($x->format("d")); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } clone $o; @@ -28,10 +28,10 @@ clone $o; try { var_dump(timezone_location_get(clone new MyDateTimezone)); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -The DateTime object has not been correctly initialized by its constructor -The DateTime object has not been correctly initialized by its constructor -The DateTimeZone object has not been correctly initialized by its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor diff --git a/ext/date/tests/bug50055.phpt b/ext/date/tests/bug50055-001.phpt similarity index 88% rename from ext/date/tests/bug50055.phpt rename to ext/date/tests/bug50055-001.phpt index 907bb93e44d26..9bff3405f52be 100644 --- a/ext/date/tests/bug50055.phpt +++ b/ext/date/tests/bug50055-001.phpt @@ -23,8 +23,8 @@ date_sub($ds2, $i); 2010-03-07T13:21:38+0000 2010-04-20T13:21:38+0000 -Warning: date_sub(): Only non-special relative time specifications are supported for subtraction in %sbug50055.php on line 9 +Warning: date_sub(): Only non-special relative time specifications are supported for subtraction in %s 2010-03-07T13:21:38+0000 2010-02-16T13:21:38+0000 -Warning: date_sub(): Only non-special relative time specifications are supported for subtraction in %sbug50055.php on line 17 +Warning: date_sub(): Only non-special relative time specifications are supported for subtraction in %s diff --git a/ext/date/tests/bug50055-002.phpt b/ext/date/tests/bug50055-002.phpt new file mode 100644 index 0000000000000..5e334666f8415 --- /dev/null +++ b/ext/date/tests/bug50055-002.phpt @@ -0,0 +1,36 @@ +--TEST-- +Bug #50555 (DateTime::sub() allows 'relative' time modifications) (OO). +--FILE-- +format( DateTime::ISO8601 ), "\n"; +echo date_add($da1, $i)->format( DateTime::ISO8601 ), "\n"; +try { + $ds1->sub($i); +} catch (DateInvalidOperationException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +//negative DateInterval +$da2 = date_create( $now ); +$ds2 = date_create( $now ); +$i2 = DateInterval::createFromDateString('third Tuesday of last month'); +echo $da2->format( DateTime::ISO8601 ), "\n"; +echo date_add($da2, $i2)->format( DateTime::ISO8601 ), "\n";//works +try { + $ds2->sub($i); +} catch (DateInvalidOperationException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} +?> +--EXPECTF-- +2010-03-07T13:21:38+0000 +2010-04-20T13:21:38+0000 +DateInvalidOperationException: DateTime::sub(): Only non-special relative time specifications are supported for subtraction +2010-03-07T13:21:38+0000 +2010-02-16T13:21:38+0000 +DateInvalidOperationException: DateTime::sub(): Only non-special relative time specifications are supported for subtraction diff --git a/ext/date/tests/bug52062.phpt b/ext/date/tests/bug52062.phpt index f967773b1cc3c..e83063fe97666 100644 --- a/ext/date/tests/bug52062.phpt +++ b/ext/date/tests/bug52062.phpt @@ -12,21 +12,21 @@ $d = new DateTime('@100000000000'); var_dump($d->format('Y-m-d H:i:s U')); try { var_dump($d->getTimestamp()); -} catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; +} catch (\DateRangeError $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; } var_dump($d->format('U')); try { $d->setTimestamp(100000000000); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } var_dump($d->format('Y-m-d H:i:s U')); try { var_dump($d->getTimestamp()); -} catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; +} catch (\DateRangeError $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; } $i = new DateInterval('PT100000000000S'); @@ -34,9 +34,9 @@ var_dump($i->format('%s')); ?> --EXPECT-- string(32) "5138-11-16 09:46:40 100000000000" -Epoch doesn't fit in a PHP integer +DateRangeError: Epoch doesn't fit in a PHP integer string(12) "100000000000" -DateTime::setTimestamp(): Argument #1 ($timestamp) must be of type int, float given +TypeError: DateTime::setTimestamp(): Argument #1 ($timestamp) must be of type int, float given string(32) "5138-11-16 09:46:40 100000000000" -Epoch doesn't fit in a PHP integer +DateRangeError: Epoch doesn't fit in a PHP integer string(10) "1215752192" diff --git a/ext/date/tests/bug52808.phpt b/ext/date/tests/bug52808.phpt index a059624fdd7a0..45568c754458d 100644 --- a/ext/date/tests/bug52808.phpt +++ b/ext/date/tests/bug52808.phpt @@ -4,9 +4,11 @@ Bug #52808 (Segfault when specifying interval as two dates) getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } } echo "==DONE==\n"; @@ -91,7 +93,7 @@ object(DateInterval)#%d (%d) { ["from_string"]=> bool(false) } -Failed to parse interval (2007-05-11T15:30:00Z/) -Failed to parse interval (2007-05-11T15:30:00Z) -Unknown or bad format (2007-05-11T15:30:00Z/:00Z) +DateMalformedIntervalStringException: Failed to parse interval (2007-05-11T15:30:00Z/) +DateMalformedIntervalStringException: Failed to parse interval (2007-05-11T15:30:00Z) +DateMalformedIntervalStringException: Unknown or bad format (2007-05-11T15:30:00Z/:00Z) ==DONE== diff --git a/ext/date/tests/bug67118.phpt b/ext/date/tests/bug67118.phpt index ee1d8efc0aa32..e5109aac02379 100644 --- a/ext/date/tests/bug67118.phpt +++ b/ext/date/tests/bug67118.phpt @@ -23,7 +23,7 @@ class mydt extends datetime new mydt("Funktionsansvarig rådgivning och juridik", "UTC"); ?> --EXPECTF-- -Fatal error: Uncaught Error: The DateTime object has not been correctly initialized by its constructor in %s:%d +Fatal error: Uncaught DateObjectError: Object of type mydt (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor in %s:%d Stack trace: #0 %s(%d): DateTime->format('Y') #1 %s(%d): mydt->__construct(%s) diff --git a/ext/date/tests/bug70245.phpt b/ext/date/tests/bug70245.phpt index cdc9d4e37a7c6..90a4447cde3d3 100644 --- a/ext/date/tests/bug70245.phpt +++ b/ext/date/tests/bug70245.phpt @@ -6,8 +6,8 @@ $d = new DateTime('2011-01-15 00:00:00'); try { var_dump(strtotime('-1 month', $d)); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -strtotime(): Argument #2 ($baseTimestamp) must be of type ?int, DateTime given +TypeError: strtotime(): Argument #2 ($baseTimestamp) must be of type ?int, DateTime given diff --git a/ext/date/tests/bug70277.phpt b/ext/date/tests/bug70277.phpt index 49df2be410379..784f042a396d3 100644 --- a/ext/date/tests/bug70277.phpt +++ b/ext/date/tests/bug70277.phpt @@ -6,14 +6,14 @@ $timezone = "Europe/Zurich\0Foo"; try { var_dump(timezone_open($timezone)); } catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { var_dump(new DateTimeZone($timezone)); } catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -timezone_open(): Argument #1 ($timezone) must not contain any null bytes -DateTimeZone::__construct(): Argument #1 ($timezone) must not contain any null bytes +ValueError: timezone_open(): Argument #1 ($timezone) must not contain any null bytes +ValueError: DateTimeZone::__construct(): Argument #1 ($timezone) must not contain any null bytes diff --git a/ext/date/tests/bug73239.phpt b/ext/date/tests/bug73239.phpt index ce86e43c2c020..a05fcf817cea0 100644 --- a/ext/date/tests/bug73239.phpt +++ b/ext/date/tests/bug73239.phpt @@ -8,7 +8,7 @@ ini_set('date.timezone', 'dummy'); try { $dt = new DateTime('now'); } catch (Exception $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECTF-- diff --git a/ext/date/tests/bug75002.phpt b/ext/date/tests/bug75002.phpt index 5c3085f316aee..2f4688eb35efe 100644 --- a/ext/date/tests/bug75002.phpt +++ b/ext/date/tests/bug75002.phpt @@ -16,7 +16,7 @@ foreach (new aaa($start) as $y) { ?> ==DONE== --EXPECTF-- -Fatal error: Uncaught Error: DatePeriod has not been initialized correctly in %sbug75002.php:%d +Fatal error: Uncaught DateObjectError: Object of type DatePeriod has not been correctly initialized by calling parent::__construct() in its constructor in %sbug75002.php:%d Stack trace: #0 {main} thrown in %sbug75002.php on line %d diff --git a/ext/date/tests/bug78139.phpt b/ext/date/tests/bug78139.phpt index 0ecf404274b03..47e5536cbaad6 100644 --- a/ext/date/tests/bug78139.phpt +++ b/ext/date/tests/bug78139.phpt @@ -20,8 +20,8 @@ foreach ($strings as $string) try { $tz = new \DateTimeZone($string); - } catch (Exception $e) { - echo $e->getMessage(), "\n"; + } catch (DateInvalidTimeZoneException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; } echo "\n\n"; @@ -41,33 +41,33 @@ Parsing 'x UTC': Warning: timezone_open(): Unknown or bad timezone (x UTC) in %sbug78139.php on line %d bool(false) -DateTimeZone::__construct(): Unknown or bad timezone (x UTC) +DateInvalidTimeZoneException: DateTimeZone::__construct(): Unknown or bad timezone (x UTC) Parsing 'xx UTC': Warning: timezone_open(): Unknown or bad timezone (xx UTC) in %sbug78139.php on line %d bool(false) -DateTimeZone::__construct(): Unknown or bad timezone (xx UTC) +DateInvalidTimeZoneException: DateTimeZone::__construct(): Unknown or bad timezone (xx UTC) Parsing 'xUTC': Warning: timezone_open(): Unknown or bad timezone (xUTC) in %sbug78139.php on line %d bool(false) -DateTimeZone::__construct(): Unknown or bad timezone (xUTC) +DateInvalidTimeZoneException: DateTimeZone::__construct(): Unknown or bad timezone (xUTC) Parsing 'UTCx': Warning: timezone_open(): Unknown or bad timezone (UTCx) in %sbug78139.php on line %d bool(false) -DateTimeZone::__construct(): Unknown or bad timezone (UTCx) +DateInvalidTimeZoneException: DateTimeZone::__construct(): Unknown or bad timezone (UTCx) Parsing 'UTC xx': Warning: timezone_open(): Unknown or bad timezone (UTC xx) in %sbug78139.php on line %d bool(false) -DateTimeZone::__construct(): Unknown or bad timezone (UTC xx) +DateInvalidTimeZoneException: DateTimeZone::__construct(): Unknown or bad timezone (UTC xx) diff --git a/ext/date/tests/date_interval_bad_format_leak.phpt b/ext/date/tests/date_interval_bad_format_leak.phpt index 15e6eb9c64a91..c2e1b89fa0346 100644 --- a/ext/date/tests/date_interval_bad_format_leak.phpt +++ b/ext/date/tests/date_interval_bad_format_leak.phpt @@ -6,23 +6,23 @@ DateInterval with bad format should not leak period try { new DateInterval('P3"D'); } catch (Exception $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { new DatePeriod('P3"D'); } catch (Exception $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { new DatePeriod('2008-03-01T12:00:00Z1'); } catch (Exception $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -Unknown or bad format (P3"D) -Unknown or bad format (P3"D) -Unknown or bad format (2008-03-01T12:00:00Z1) +DateMalformedIntervalStringException: Unknown or bad format (P3"D) +DateMalformedPeriodStringException: Unknown or bad format (P3"D) +DateMalformedPeriodStringException: Unknown or bad format (2008-03-01T12:00:00Z1) diff --git a/ext/date/tests/date_interval_create_from_date_string_broken.phpt b/ext/date/tests/date_interval_create_from_date_string_broken.phpt index c065de0f8c1ce..e3954b4895f5a 100644 --- a/ext/date/tests/date_interval_create_from_date_string_broken.phpt +++ b/ext/date/tests/date_interval_create_from_date_string_broken.phpt @@ -6,5 +6,5 @@ $i = date_interval_create_from_date_string("foobar"); var_dump($i); ?> --EXPECTF-- -Warning: date_interval_create_from_date_string(): Unknown or bad format (foobar) at position 0 (f): The timezone could not be found in the database in %sdate_interval_create_from_date_string_broken.php on line 2 +Warning: date_interval_create_from_date_string(): Unknown or bad format (foobar) at position 0 (f): The timezone could not be found in the database in %s bool(false) diff --git a/ext/date/tests/date_interval_create_from_date_string_nullparam.phpt b/ext/date/tests/date_interval_create_from_date_string_nullparam.phpt index afac12b7a33a4..1a4a17d786cfe 100644 --- a/ext/date/tests/date_interval_create_from_date_string_nullparam.phpt +++ b/ext/date/tests/date_interval_create_from_date_string_nullparam.phpt @@ -10,5 +10,5 @@ var_dump($i); --EXPECTF-- Deprecated: date_interval_create_from_date_string(): Passing null to parameter #1 ($datetime) of type string is deprecated in %s on line %d -Warning: date_interval_create_from_date_string(): Unknown or bad format () at position 0 ( ): Empty string in %sdate_interval_create_from_date_string_nullparam.php on line 2 +Warning: date_interval_create_from_date_string(): Unknown or bad format () at position 0 ( ): Empty string in %s bool(false) diff --git a/ext/date/tests/date_interval_non_relative_warning.phpt b/ext/date/tests/date_interval_non_relative_warning.phpt index fc0b246277940..9830c067e29ba 100644 --- a/ext/date/tests/date_interval_non_relative_warning.phpt +++ b/ext/date/tests/date_interval_non_relative_warning.phpt @@ -10,27 +10,31 @@ $formats = [ ]; foreach ($formats as $format) { - $d = DateInterval::createFromDateString($format); + try { + $d = DateInterval::createFromDateString($format); + } catch (DateMalformedIntervalStringException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; + } } +echo "====\n"; + foreach ($formats as $format) { $d = date_interval_create_from_date_string($format); } ?> --EXPECTF-- -Warning: DateInterval::createFromDateString(): String 'next weekday 15:30' contains non-relative elements in %sdate_interval_non_relative_warning.php on line %d - -Warning: DateInterval::createFromDateString(): String '+5 hours noon' contains non-relative elements in %sdate_interval_non_relative_warning.php on line %d - -Warning: DateInterval::createFromDateString(): String '-8 days March 23' contains non-relative elements in %sdate_interval_non_relative_warning.php on line %d - -Warning: DateInterval::createFromDateString(): String '+72 seconds UTC' contains non-relative elements in %sdate_interval_non_relative_warning.php on line %d +DateMalformedIntervalStringException: String 'next weekday 15:30' contains non-relative elements +DateMalformedIntervalStringException: String '+5 hours noon' contains non-relative elements +DateMalformedIntervalStringException: String '-8 days March 23' contains non-relative elements +DateMalformedIntervalStringException: String '+72 seconds UTC' contains non-relative elements +==== -Warning: date_interval_create_from_date_string(): String 'next weekday 15:30' contains non-relative elements in %sdate_interval_non_relative_warning.php on line %d +Warning: date_interval_create_from_date_string(): String 'next weekday 15:30' contains non-relative elements in %s on line %d -Warning: date_interval_create_from_date_string(): String '+5 hours noon' contains non-relative elements in %sdate_interval_non_relative_warning.php on line %d +Warning: date_interval_create_from_date_string(): String '+5 hours noon' contains non-relative elements in %s on line %d -Warning: date_interval_create_from_date_string(): String '-8 days March 23' contains non-relative elements in %sdate_interval_non_relative_warning.php on line %d +Warning: date_interval_create_from_date_string(): String '-8 days March 23' contains non-relative elements in %s on line %d -Warning: date_interval_create_from_date_string(): String '+72 seconds UTC' contains non-relative elements in %sdate_interval_non_relative_warning.php on line %d +Warning: date_interval_create_from_date_string(): String '+72 seconds UTC' contains non-relative elements in %s on line %d diff --git a/ext/date/tests/date_period_bad_iso_format.phpt b/ext/date/tests/date_period_bad_iso_format.phpt index fecc4fa23ceab..e0e8efdc2a29f 100644 --- a/ext/date/tests/date_period_bad_iso_format.phpt +++ b/ext/date/tests/date_period_bad_iso_format.phpt @@ -6,24 +6,24 @@ Test bad ISO date formats passed to DatePeriod constructor try { new DatePeriod("R4"); } catch (Exception $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { new DatePeriod("R4/2012-07-01T00:00:00Z"); } catch (Exception $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { new DatePeriod("2012-07-01T00:00:00Z/P7D"); } catch (Exception $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -DatePeriod::__construct(): ISO interval must contain a start date, "R4" given -DatePeriod::__construct(): ISO interval must contain an interval, "R4/2012-07-01T00:00:00Z" given -DatePeriod::__construct(): ISO interval must contain an end date or a recurrence count, "2012-07-01T00:00:00Z/P7D" given +DateMalformedPeriodStringException: DatePeriod::__construct(): ISO interval must contain a start date, "R4" given +DateMalformedPeriodStringException: DatePeriod::__construct(): ISO interval must contain an interval, "R4/2012-07-01T00:00:00Z" given +DateMalformedPeriodStringException: DatePeriod::__construct(): ISO interval must contain an end date or a recurrence count, "2012-07-01T00:00:00Z/P7D" given diff --git a/ext/date/tests/date_period_set_state2.phpt b/ext/date/tests/date_period_set_state2.phpt index 7d77a632dc7e2..61d0133a66363 100644 --- a/ext/date/tests/date_period_set_state2.phpt +++ b/ext/date/tests/date_period_set_state2.phpt @@ -9,10 +9,10 @@ try { "start" => new DateTime, ] ); -} catch (\Error $exception) { - echo $exception->getMessage() . "\n"; +} catch (\Error $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object diff --git a/ext/date/tests/date_period_unserialize2.phpt b/ext/date/tests/date_period_unserialize2.phpt index c368155dbe83e..5ea2466da8e97 100644 --- a/ext/date/tests/date_period_unserialize2.phpt +++ b/ext/date/tests/date_period_unserialize2.phpt @@ -14,10 +14,10 @@ try { "start" => new DateTime, ] ); -} catch (\Error $exception) { - echo $exception->getMessage() . "\n"; +} catch (\Error $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object diff --git a/ext/date/tests/date_period_unserialize3.phpt b/ext/date/tests/date_period_unserialize3.phpt index 4213320e30ae2..d5d4a57456d9a 100644 --- a/ext/date/tests/date_period_unserialize3.phpt +++ b/ext/date/tests/date_period_unserialize3.phpt @@ -20,15 +20,15 @@ try { "include_end_date" => true, ] ); -} catch (\Error $exception) { - echo $exception->getMessage() . "\n"; +} catch (\Error $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; } var_dump($period); ?> --EXPECTF-- -Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object object(DatePeriod)#%d (%d) { ["start"]=> object(DateTime)#%d (%d) { diff --git a/ext/date/tests/mktime_error.phpt b/ext/date/tests/mktime_error.phpt index 5bd1421369b9c..f333580b037b0 100644 --- a/ext/date/tests/mktime_error.phpt +++ b/ext/date/tests/mktime_error.phpt @@ -1,8 +1,8 @@ --TEST-- -Test mktime() function : error conditions +Test mktime() function: error conditions --FILE-- getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } echo "\n-- Testing mktime() function with more than expected no. of arguments --\n"; @@ -25,7 +25,7 @@ $extra_arg = 10; try { var_dump( mktime($hour, $minute, $sec, $month, $day, $year, $extra_arg) ); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> @@ -33,7 +33,7 @@ try { *** Testing mktime() : error conditions *** -- Testing mktime() function with Zero arguments -- -mktime() expects at least 1 argument, 0 given +ArgumentCountError: mktime() expects at least 1 argument, 0 given -- Testing mktime() function with more than expected no. of arguments -- -mktime() expects at most 6 arguments, 7 given +ArgumentCountError: mktime() expects at most 6 arguments, 7 given diff --git a/ext/date/tests/oo_001.phpt b/ext/date/tests/oo_001.phpt index 5db101f858671..4cae1f8e41a4e 100644 --- a/ext/date/tests/oo_001.phpt +++ b/ext/date/tests/oo_001.phpt @@ -23,13 +23,13 @@ try { $d = new _d; var_dump($d->format("Y-m-d H:i:s")); } catch (Error $e) { - echo $e->getMessage(),"\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { new DateTime("1am todax"); } catch (Exception $e) { - echo $e->getMessage(),"\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } $t = new DateTimeZone("UTC"); @@ -39,36 +39,36 @@ try { $t = new _t; var_dump($t->getName()); } catch (Error $e) { - echo $e->getMessage(),"\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { new DateTimeZone("GottaFindThisOne"); -} catch (Exception $e) { - echo $e->getMessage(),"\n"; +} catch (DateInvalidTimeZoneException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; } $p = new _p; try { var_dump($p->getStartDate()); } catch (Error $e) { - echo $e->getMessage(),"\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { var_dump($p->getDateInterval()); } catch (Error $e) { - echo $e->getMessage(),"\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } echo "DONE\n"; ?> --EXPECTF-- string(19) "%d-%d-%d %d:%d:%d" -The DateTime object has not been correctly initialized by its constructor -Failed to parse time string (1am todax) at position 4 (t): The timezone could not be found in the database +DateObjectError: Object of type _d (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateMalformedStringException: Failed to parse time string (1am todax) at position 4 (t): The timezone could not be found in the database string(3) "UTC" -The DateTimeZone object has not been correctly initialized by its constructor -DateTimeZone::__construct(): Unknown or bad timezone (GottaFindThisOne) -The DatePeriod object has not been correctly initialized by its constructor -The DatePeriod object has not been correctly initialized by its constructor +DateObjectError: Object of type _t (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor +DateInvalidTimeZoneException: DateTimeZone::__construct(): Unknown or bad timezone (GottaFindThisOne) +DateObjectError: Object of type _p (inheriting DatePeriod) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type _p (inheriting DatePeriod) has not been correctly initialized by calling parent::__construct() in its constructor DONE diff --git a/ext/date/tests/timezone_identifiers_list_wrong_constructor.phpt b/ext/date/tests/timezone_identifiers_list_wrong_constructor.phpt index 0a697dd78fc84..2c2b603f8980f 100644 --- a/ext/date/tests/timezone_identifiers_list_wrong_constructor.phpt +++ b/ext/date/tests/timezone_identifiers_list_wrong_constructor.phpt @@ -10,15 +10,15 @@ date.timezone=UTC try { var_dump(timezone_identifiers_list(DateTimeZone::PER_COUNTRY)); } catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { var_dump(timezone_identifiers_list(DateTimeZone::PER_COUNTRY, 'A')); } catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -timezone_identifiers_list(): Argument #2 ($countryCode) must be a two-letter ISO 3166-1 compatible country code when argument #1 ($timezoneGroup) is DateTimeZone::PER_COUNTRY -timezone_identifiers_list(): Argument #2 ($countryCode) must be a two-letter ISO 3166-1 compatible country code when argument #1 ($timezoneGroup) is DateTimeZone::PER_COUNTRY +ValueError: timezone_identifiers_list(): Argument #2 ($countryCode) must be a two-letter ISO 3166-1 compatible country code when argument #1 ($timezoneGroup) is DateTimeZone::PER_COUNTRY +ValueError: timezone_identifiers_list(): Argument #2 ($countryCode) must be a two-letter ISO 3166-1 compatible country code when argument #1 ($timezoneGroup) is DateTimeZone::PER_COUNTRY diff --git a/ext/date/tests/timezone_open_warning.phpt b/ext/date/tests/timezone_open_warning.phpt new file mode 100644 index 0000000000000..012192beef453 --- /dev/null +++ b/ext/date/tests/timezone_open_warning.phpt @@ -0,0 +1,23 @@ +--TEST-- +timezone_open() invalid timezones +--FILE-- +getName(), "\n"; + } +} +?> +--EXPECTF-- +In: +02:30; Out: +02:30 +In: Europe/Kyiv; Out: Europe/Kyiv + +Warning: timezone_open(): Unknown or bad timezone (2.5) in %stimezone_open_warning.php on line 6 + +Warning: timezone_open(): Unknown or bad timezone (99:60) in %stimezone_open_warning.php on line 6 + +Warning: timezone_open(): Unknown or bad timezone (Europe/Lviv) in %stimezone_open_warning.php on line 6 diff --git a/ext/intl/tests/dateformat_formatObject_error.phpt b/ext/intl/tests/dateformat_formatObject_error.phpt index 9f5a43c831f2b..839cb27d317c9 100644 --- a/ext/intl/tests/dateformat_formatObject_error.phpt +++ b/ext/intl/tests/dateformat_formatObject_error.phpt @@ -36,7 +36,7 @@ Warning: IntlDateFormatter::formatObject(): datefmt_format_object: bad IntlCalen bool(false) Warning: IntlDateFormatter::formatObject(): datefmt_format_object: error calling ::getTimeStamp() on the object in %s on line %d -The DateTime object has not been correctly initialized by its constructor +Object of type B (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor Warning: IntlDateFormatter::formatObject(): datefmt_format_object: the date/time format type is invalid in %s on line %d bool(false)