Skip to content

Commit

Permalink
Make DateTime and DateTimeImmutable siblings.
Browse files Browse the repository at this point in the history
They both implement the DateTimeInterface interface, which specifies the
non-modifying methods of DateTime/DateTimeImmutable.
  • Loading branch information
derickr committed Mar 31, 2013
1 parent 0e25e00 commit 68a7fec
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 131 deletions.
69 changes: 46 additions & 23 deletions ext/date/php_date.c
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,16 @@ const zend_function_entry date_functions[] = {
PHP_FE_END
};

static const zend_function_entry date_funcs_interface[] = {
PHP_ABSTRACT_ME(DateTimeInterface, format, arginfo_date_method_format)
PHP_ABSTRACT_ME(DateTimeInterface, getTimezone, arginfo_date_method_timezone_get)
PHP_ABSTRACT_ME(DateTimeInterface, getOffset, arginfo_date_method_offset_get)
PHP_ABSTRACT_ME(DateTimeInterface, getTimestamp, arginfo_date_method_timestamp_get)
PHP_ABSTRACT_ME(DateTimeInterface, diff, arginfo_date_method_diff)
PHP_ABSTRACT_ME(DateTimeInterface, __wakeup, NULL)
PHP_FE_END
};

const zend_function_entry date_funcs_date[] = {
PHP_ME(DateTime, __construct, arginfo_date_create, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
PHP_ME(DateTime, __wakeup, NULL, ZEND_ACC_PUBLIC)
Expand All @@ -468,7 +478,15 @@ const zend_function_entry date_funcs_date[] = {

const zend_function_entry date_funcs_immutable[] = {
PHP_ME(DateTimeImmutable, __construct, arginfo_date_create, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
PHP_ME(DateTime, __wakeup, NULL, ZEND_ACC_PUBLIC)
PHP_ME(DateTimeImmutable, __set_state, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME_MAPPING(createFromFormat, date_create_from_format, arginfo_date_create_from_format, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME_MAPPING(getLastErrors, date_get_last_errors, arginfo_date_get_last_errors, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME_MAPPING(format, date_format, arginfo_date_method_format, 0)
PHP_ME_MAPPING(getTimezone, date_timezone_get, arginfo_date_method_timezone_get, 0)
PHP_ME_MAPPING(getOffset, date_offset_get, arginfo_date_method_offset_get, 0)
PHP_ME_MAPPING(getTimestamp, date_timestamp_get, arginfo_date_method_timestamp_get, 0)
PHP_ME_MAPPING(diff, date_diff, arginfo_date_method_diff, 0)
PHP_ME(DateTimeImmutable, modify, arginfo_date_method_modify, 0)
PHP_ME(DateTimeImmutable, add, arginfo_date_method_add, 0)
PHP_ME(DateTimeImmutable, sub, arginfo_date_method_sub, 0)
Expand Down Expand Up @@ -540,7 +558,7 @@ PHP_INI_END()
/* }}} */

zend_class_entry *date_ce_date, *date_ce_timezone, *date_ce_interval, *date_ce_period;
zend_class_entry *date_ce_immutable;
zend_class_entry *date_ce_immutable, *date_ce_interface;


PHPAPI zend_class_entry *php_date_get_date_ce(void)
Expand Down Expand Up @@ -1955,7 +1973,10 @@ zend_object_iterator *date_object_period_get_iterator(zend_class_entry *ce, zval

static void date_register_classes(TSRMLS_D)
{
zend_class_entry ce_date, ce_immutable, ce_timezone, ce_interval, ce_period;
zend_class_entry ce_date, ce_immutable, ce_timezone, ce_interval, ce_period, ce_interface;

INIT_CLASS_ENTRY(ce_interface, "DateTimeInterface", date_funcs_interface);
date_ce_interface = zend_register_internal_interface(&ce_interface TSRMLS_CC);

INIT_CLASS_ENTRY(ce_date, "DateTime", date_funcs_date);
ce_date.create_object = date_object_new_date;
Expand All @@ -1965,6 +1986,7 @@ static void date_register_classes(TSRMLS_D)
date_object_handlers_date.compare_objects = date_object_compare_date;
date_object_handlers_date.get_properties = date_object_get_properties;
date_object_handlers_date.get_gc = date_object_get_gc;
zend_class_implements(date_ce_date TSRMLS_CC, 1, date_ce_interface);

#define REGISTER_DATE_CLASS_CONST_STRING(const_name, value) \
zend_declare_class_constant_stringl(date_ce_date, const_name, sizeof(const_name)-1, value, sizeof(value)-1 TSRMLS_CC);
Expand All @@ -1983,11 +2005,12 @@ static void date_register_classes(TSRMLS_D)

INIT_CLASS_ENTRY(ce_immutable, "DateTimeImmutable", date_funcs_immutable);
ce_immutable.create_object = date_object_new_date;
date_ce_immutable = zend_register_internal_class_ex(&ce_immutable, date_ce_date, "DateTime" TSRMLS_CC);
date_ce_immutable = zend_register_internal_class_ex(&ce_immutable, NULL, NULL TSRMLS_CC);
memcpy(&date_object_handlers_immutable, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
date_object_handlers_immutable.clone_obj = date_object_clone_date;
date_object_handlers_immutable.compare_objects = date_object_compare_date;
date_object_handlers_immutable.get_properties = date_object_get_properties;
zend_class_implements(date_ce_immutable TSRMLS_CC, 1, date_ce_interface);

INIT_CLASS_ENTRY(ce_timezone, "DateTimeZone", date_funcs_timezone);
ce_timezone.create_object = date_object_new_timezone;
Expand Down Expand Up @@ -2761,7 +2784,7 @@ PHP_METHOD(DateTime, __wakeup)
myht = Z_OBJPROP_P(object);

if (!php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC)) {
php_error(E_ERROR, "Invalid serialization data for DateTime object");
php_error(E_ERROR, "Invalid serialization data for DateTimeInterface object");
}
}
/* }}} */
Expand Down Expand Up @@ -2916,7 +2939,7 @@ PHP_FUNCTION(date_parse_from_format)
}
/* }}} */

/* {{{ proto string date_format(DateTime object, string format)
/* {{{ proto string date_format(DateTimeInterface object, string format)
Returns date formatted according to given format
*/
PHP_FUNCTION(date_format)
Expand All @@ -2926,7 +2949,7 @@ PHP_FUNCTION(date_format)
char *format;
int format_len;

if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date, &format, &format_len) == FAILURE) {
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_interface, &format, &format_len) == FAILURE) {
RETURN_FALSE;
}
dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
Expand Down Expand Up @@ -3026,7 +3049,7 @@ PHP_METHOD(DateTimeImmutable, modify)
char *modify;
int modify_len;

if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date, &modify, &modify_len) == FAILURE) {
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_immutable, &modify, &modify_len) == FAILURE) {
RETURN_FALSE;
}

Expand Down Expand Up @@ -3095,7 +3118,7 @@ PHP_METHOD(DateTimeImmutable, add)
{
zval *object, *interval, *new_object;

if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) {
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_immutable, &interval, date_ce_interval) == FAILURE) {
RETURN_FALSE;
}

Expand Down Expand Up @@ -3165,7 +3188,7 @@ PHP_METHOD(DateTimeImmutable, sub)
{
zval *object, *interval, *new_object;

if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) {
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_immutable, &interval, date_ce_interval) == FAILURE) {
RETURN_FALSE;
}

Expand All @@ -3176,7 +3199,7 @@ PHP_METHOD(DateTimeImmutable, sub)
}
/* }}} */

/* {{{ proto DateTimeZone date_timezone_get(DateTime object)
/* {{{ proto DateTimeZone date_timezone_get(DateTimeInterface object)
Return new DateTimeZone object relative to give DateTime
*/
PHP_FUNCTION(date_timezone_get)
Expand All @@ -3185,7 +3208,7 @@ PHP_FUNCTION(date_timezone_get)
php_date_obj *dateobj;
php_timezone_obj *tzobj;

if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) {
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_interface) == FAILURE) {
RETURN_FALSE;
}
dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
Expand Down Expand Up @@ -3255,7 +3278,7 @@ PHP_METHOD(DateTimeImmutable, setTimezone)
zval *object, *new_object;
zval *timezone_object;

if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &timezone_object, date_ce_timezone) == FAILURE) {
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_immutable, &timezone_object, date_ce_timezone) == FAILURE) {
RETURN_FALSE;
}

Expand All @@ -3266,7 +3289,7 @@ PHP_METHOD(DateTimeImmutable, setTimezone)
}
/* }}} */

/* {{{ proto long date_offset_get(DateTime object)
/* {{{ proto long date_offset_get(DateTimeInterface object)
Returns the DST offset.
*/
PHP_FUNCTION(date_offset_get)
Expand All @@ -3275,7 +3298,7 @@ PHP_FUNCTION(date_offset_get)
php_date_obj *dateobj;
timelib_time_offset *offset;

if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) {
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_interface) == FAILURE) {
RETURN_FALSE;
}
dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
Expand Down Expand Up @@ -3338,7 +3361,7 @@ PHP_METHOD(DateTimeImmutable, setTime)
zval *object, *new_object;
long h, i, s = 0;

if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_date, &h, &i, &s) == FAILURE) {
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_immutable, &h, &i, &s) == FAILURE) {
RETURN_FALSE;
}

Expand Down Expand Up @@ -3386,7 +3409,7 @@ PHP_METHOD(DateTimeImmutable, setDate)
zval *object, *new_object;
long y, m, d;

if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Olll", &object, date_ce_date, &y, &m, &d) == FAILURE) {
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Olll", &object, date_ce_immutable, &y, &m, &d) == FAILURE) {
RETURN_FALSE;
}

Expand Down Expand Up @@ -3438,7 +3461,7 @@ PHP_METHOD(DateTimeImmutable, setISODate)
zval *object, *new_object;
long y, w, d = 1;

if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_date, &y, &w, &d) == FAILURE) {
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_immutable, &y, &w, &d) == FAILURE) {
RETURN_FALSE;
}

Expand Down Expand Up @@ -3484,7 +3507,7 @@ PHP_METHOD(DateTimeImmutable, setTimestamp)
zval *object, *new_object;
long timestamp;

if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &object, date_ce_date, &timestamp) == FAILURE) {
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &object, date_ce_immutable, &timestamp) == FAILURE) {
RETURN_FALSE;
}

Expand All @@ -3495,7 +3518,7 @@ PHP_METHOD(DateTimeImmutable, setTimestamp)
}
/* }}} */

/* {{{ proto long date_timestamp_get(DateTime object)
/* {{{ proto long date_timestamp_get(DateTimeInterface object)
Gets the Unix timestamp.
*/
PHP_FUNCTION(date_timestamp_get)
Expand All @@ -3505,7 +3528,7 @@ PHP_FUNCTION(date_timestamp_get)
long timestamp;
int error;

if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) {
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_interface) == FAILURE) {
RETURN_FALSE;
}
dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
Expand Down Expand Up @@ -4231,10 +4254,10 @@ PHP_METHOD(DatePeriod, __construct)
zend_error_handling error_handling;

zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "OOl|l", &start, date_ce_date, &interval, date_ce_interval, &recurrences, &options) == FAILURE) {
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "OOO|l", &start, date_ce_date, &interval, date_ce_interval, &end, date_ce_date, &options) == FAILURE) {
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "OOl|l", &start, date_ce_interface, &interval, date_ce_interval, &recurrences, &options) == FAILURE) {
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "OOO|l", &start, date_ce_interface, &interval, date_ce_interval, &end, date_ce_date, &options) == FAILURE) {
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &isostr, &isostr_len, &options) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "This constructor accepts either (DateTime, DateInterval, int) OR (DateTime, DateInterval, DateTime) OR (string) as arguments.");
php_error_docref(NULL TSRMLS_CC, E_WARNING, "This constructor accepts either (DateTimeInterface, DateInterval, int) OR (DateTimeInterface, DateInterval, DateTime) OR (string) as arguments.");
zend_restore_error_handling(&error_handling TSRMLS_CC);
return;
}
Expand Down
4 changes: 2 additions & 2 deletions ext/date/tests/DatePeriod_wrong_constructor.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ date.timezone=UTC
new DatePeriod();
?>
--EXPECTF--
Fatal error: Uncaught exception 'Exception' with message 'DatePeriod::__construct(): This constructor accepts either (DateTime, DateInterval, int) OR (DateTime, DateInterval, DateTime) OR (string) as arguments.' in %s:%d
Fatal error: Uncaught exception 'Exception' with message 'DatePeriod::__construct(): This constructor accepts either (DateTimeInterface, DateInterval, int) OR (DateTimeInterface, DateInterval, DateTime) OR (string) as arguments.' in %s:%d
Stack trace:
#0 %s(%d): DatePeriod->__construct()
#1 {main}
thrown in %s on line %d
thrown in %s on line %d
6 changes: 3 additions & 3 deletions ext/date/tests/date_format_error.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ bool(false)

-- Testing date_create() function with an invalid values for $object argument --

Warning: date_format() expects parameter 1 to be DateTime, object given in %sp on line %d
Warning: date_format() expects parameter 1 to be DateTimeInterface, object given in %sp on line %d
bool(false)

Warning: date_format() expects parameter 1 to be DateTime, integer given in %s on line %d
Warning: date_format() expects parameter 1 to be DateTimeInterface, integer given in %s on line %d
bool(false)

Warning: date_format() expects parameter 1 to be DateTime, null given in %s on line %d
Warning: date_format() expects parameter 1 to be DateTimeInterface, null given in %s on line %d
bool(false)
===DONE===
Loading

2 comments on commit 68a7fec

@reeze
Copy link
Contributor

@reeze reeze commented on 68a7fec Mar 31, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,

[ext/date/tests/bug55397.phpt]
[ext/date/tests/bug62852.phpt]
[ext/date/tests/bug62852_var2.phpt]
[ext/date/tests/bug62852_var3.phpt]

+ Fatal error: Invalid serialization data for DateTimeInterface object in /Users/reeze/Opens
- Fatal error: Invalid serialization data for DateTime object in %sbug55397.php on line %d

@laruence
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 2f6b9b9

Please sign in to comment.