From 30d0ae42b56c62bc441d763dfa8388c43625b83d Mon Sep 17 00:00:00 2001 From: Lonny Kapelushnik Date: Fri, 28 Sep 2012 12:15:20 +0000 Subject: Bug 54567 DateTimeZone serialize/unserialize Make DateTimeZone serializable and implement __set_state --- ext/date/php_date.c | 115 +++++++++++++++++++++++ ext/date/php_date.h | 3 + ext/date/tests/014.phpt | 6 +- ext/date/tests/DateTimeZone_clone_basic1.phpt | 12 ++- ext/date/tests/DateTimeZone_clone_basic2.phpt | 24 ++++- ext/date/tests/DateTimeZone_clone_basic3.phpt | 30 +++++- ext/date/tests/DateTimeZone_construct_basic.phpt | 18 +++- ext/date/tests/DateTimeZone_serialize.phpt | 20 ++-- ext/date/tests/DateTimeZone_verify.phpt | 26 +++-- ext/date/tests/timezone_open_basic1.phpt | 18 +++- 10 files changed, 241 insertions(+), 31 deletions(-) (limited to 'ext') diff --git a/ext/date/php_date.c b/ext/date/php_date.c index c61a4d3610..16eb6dbe82 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -500,6 +500,8 @@ const zend_function_entry date_funcs_immutable[] = { const zend_function_entry date_funcs_timezone[] = { PHP_ME(DateTimeZone, __construct, arginfo_timezone_open, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC) + PHP_ME(DateTimeZone, __wakeup, NULL, ZEND_ACC_PUBLIC) + PHP_ME(DateTimeZone, __set_state, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME_MAPPING(getName, timezone_name_get, arginfo_timezone_method_name_get, 0) PHP_ME_MAPPING(getOffset, timezone_offset_get, arginfo_timezone_method_offset_get, 0) PHP_ME_MAPPING(getTransitions, timezone_transitions_get, arginfo_timezone_method_transitions_get, 0) @@ -630,6 +632,7 @@ static HashTable *date_object_get_gc_interval(zval *object, zval ***table, int * static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC); static HashTable *date_object_get_gc_period(zval *object, zval ***table, int *n TSRMLS_DC); static HashTable *date_object_get_properties_period(zval *object TSRMLS_DC); +static HashTable *date_object_get_properties_timezone(zval *object TSRMLS_DC); zval *date_interval_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC); void date_interval_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC); @@ -2017,6 +2020,7 @@ static void date_register_classes(TSRMLS_D) date_ce_timezone = zend_register_internal_class_ex(&ce_timezone, NULL, NULL TSRMLS_CC); memcpy(&date_object_handlers_timezone, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); date_object_handlers_timezone.clone_obj = date_object_clone_timezone; + date_object_handlers_timezone.get_properties = date_object_get_properties_timezone; #define REGISTER_TIMEZONE_CLASS_CONST_STRING(const_name, value) \ zend_declare_class_constant_long(date_ce_timezone, const_name, sizeof(const_name)-1, value TSRMLS_CC); @@ -2269,6 +2273,50 @@ static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC) return new_ov; } +static HashTable *date_object_get_properties_timezone(zval *object TSRMLS_DC) +{ + HashTable *props; + zval *zv; + php_timezone_obj *tzobj; + + + tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC); + + props = zend_std_get_properties(object TSRMLS_CC); + + if (!tzobj->initialized || GC_G(gc_active)) { + return props; + } + + MAKE_STD_ZVAL(zv); + ZVAL_LONG(zv, tzobj->type); + zend_hash_update(props, "timezone_type", 14, &zv, sizeof(zval), NULL); + + MAKE_STD_ZVAL(zv); + switch (tzobj->type) { + case TIMELIB_ZONETYPE_ID: + ZVAL_STRING(zv, tzobj->tzi.tz->name, 1); + break; + case TIMELIB_ZONETYPE_OFFSET: { + char *tmpstr = emalloc(sizeof("UTC+05:00")); + + snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d", + tzobj->tzi.z.utc_offset > 0 ? '-' : '+', + abs(tzobj->tzi.z.utc_offset / 60), + abs((tzobj->tzi.z.utc_offset % 60))); + + ZVAL_STRING(zv, tmpstr, 0); + } + break; + case TIMELIB_ZONETYPE_ABBR: + ZVAL_STRING(zv, tzobj->tzi.tz->timezone_abbr, 1); + break; + } + zend_hash_update(props, "timezone", 9, &zv, sizeof(zval), NULL); + + return props; +} + static inline zend_object_value date_object_new_interval_ex(zend_class_entry *class_type, php_interval_obj **ptr TSRMLS_DC) { php_interval_obj *intern; @@ -3643,6 +3691,73 @@ PHP_METHOD(DateTimeZone, __construct) } /* }}} */ +static int php_date_timezone_initialize_from_hash(zval **return_value, php_timezone_obj **tzobj, HashTable *myht TSRMLS_DC) +{ + zval **z_timezone = NULL; + zval **z_timezone_type = NULL; + timelib_tzinfo *tzi; + + if (zend_hash_find(myht, "timezone_type", 14, (void**) &z_timezone_type) == SUCCESS) { + if (zend_hash_find(myht, "timezone", 9, (void**) &z_timezone) == SUCCESS) { + convert_to_long(*z_timezone_type); + switch (Z_LVAL_PP(z_timezone_type)) { + case TIMELIB_ZONETYPE_OFFSET: + (*tzobj)->type = TIMELIB_ZONETYPE_OFFSET; + (*tzobj)->tzi.utc_offset = Z_LVAL_PP(z_timezone); + break; + case TIMELIB_ZONETYPE_ABBR: + (*tzobj)->type = TIMELIB_ZONETYPE_ABBR; + (*tzobj)->tzi.z.utc_offset = Z_LVAL_PP(z_timezone); + break; + case TIMELIB_ZONETYPE_ID: + if (SUCCESS == timezone_initialize(&tzi, Z_STRVAL_PP(z_timezone) TSRMLS_CC)) { + (*tzobj)->type = TIMELIB_ZONETYPE_ID; + (*tzobj)->tzi.tz = tzi; + (*tzobj)->initialized = 1; + return 1; + } + } + } + } + return 0; +} + +/* {{{ proto DateTimeZone::__set_state() + * */ +PHP_METHOD(DateTimeZone, __set_state) +{ + php_timezone_obj *tzobj; + zval *array; + HashTable *myht; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) { + RETURN_FALSE; + } + + myht = HASH_OF(array); + + php_date_instantiate(date_ce_timezone, return_value TSRMLS_CC); + tzobj = (php_timezone_obj *) zend_object_store_get_object(return_value TSRMLS_CC); + php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto DateTimeZone::__wakeup() + * */ +PHP_METHOD(DateTimeZone, __wakeup) +{ + zval *object = getThis(); + php_timezone_obj *tzobj; + HashTable *myht; + + tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC); + + myht = Z_OBJPROP_P(object); + + php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht TSRMLS_CC); +} +/* }}} */ + /* {{{ proto string timezone_name_get(DateTimeZone object) Returns the name of the timezone. */ diff --git a/ext/date/php_date.h b/ext/date/php_date.h index efae0a1db8..725590136c 100644 --- a/ext/date/php_date.h +++ b/ext/date/php_date.h @@ -84,6 +84,8 @@ PHP_METHOD(DateTimeImmutable, setISODate); PHP_METHOD(DateTimeImmutable, setTimestamp); PHP_METHOD(DateTimeZone, __construct); +PHP_METHOD(DateTimeZone, __wakeup); +PHP_METHOD(DateTimeZone, __set_state); PHP_FUNCTION(timezone_open); PHP_FUNCTION(timezone_name_get); PHP_FUNCTION(timezone_name_from_abbr); @@ -144,6 +146,7 @@ struct _php_timezone_obj { int dst; } z; } tzi; + HashTable *props; }; struct _php_interval_obj { diff --git a/ext/date/tests/014.phpt b/ext/date/tests/014.phpt index be0847777f..5e609c8685 100644 --- a/ext/date/tests/014.phpt +++ b/ext/date/tests/014.phpt @@ -26,7 +26,11 @@ object(DateTime)#%d (3) { ["timezone"]=> string(3) "UTC" } -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" } Warning: timezone_offset_get() expects exactly 2 parameters, 0 given in %s on line %d diff --git a/ext/date/tests/DateTimeZone_clone_basic1.phpt b/ext/date/tests/DateTimeZone_clone_basic1.phpt index 6de5d4b463..a89005aaec 100644 --- a/ext/date/tests/DateTimeZone_clone_basic1.phpt +++ b/ext/date/tests/DateTimeZone_clone_basic1.phpt @@ -29,9 +29,17 @@ if ($clone != $orig) { ===DONE=== --EXPECTF-- *** Testing clone on DateTime objects *** -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" } -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" } TEST PASSED : Objects equal but not indetical ===DONE=== diff --git a/ext/date/tests/DateTimeZone_clone_basic2.phpt b/ext/date/tests/DateTimeZone_clone_basic2.phpt index a499510ff9..92f833082f 100644 --- a/ext/date/tests/DateTimeZone_clone_basic2.phpt +++ b/ext/date/tests/DateTimeZone_clone_basic2.phpt @@ -31,19 +31,27 @@ var_dump($d2_clone); ===DONE=== --EXPECTF-- *** Testing clone on objects whoose class derived from DateTimeZone class *** -object(DateTimeZoneExt1)#%d (2) { +object(DateTimeZoneExt1)#%d (4) { ["property1"]=> int(99) ["property2"]=> string(5) "Hello" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" } -object(DateTimeZoneExt1)#%d (2) { +object(DateTimeZoneExt1)#%d (4) { ["property1"]=> int(99) ["property2"]=> string(5) "Hello" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" } -object(DateTimeZoneExt2)#%d (4) { +object(DateTimeZoneExt2)#%d (6) { ["property3"]=> bool(true) ["property4"]=> @@ -52,8 +60,12 @@ object(DateTimeZoneExt2)#%d (4) { int(99) ["property2"]=> string(5) "Hello" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" } -object(DateTimeZoneExt2)#%d (4) { +object(DateTimeZoneExt2)#%d (6) { ["property3"]=> bool(true) ["property4"]=> @@ -62,5 +74,9 @@ object(DateTimeZoneExt2)#%d (4) { int(99) ["property2"]=> string(5) "Hello" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" } ===DONE=== diff --git a/ext/date/tests/DateTimeZone_clone_basic3.phpt b/ext/date/tests/DateTimeZone_clone_basic3.phpt index e85f42e876..128c8ff40b 100644 --- a/ext/date/tests/DateTimeZone_clone_basic3.phpt +++ b/ext/date/tests/DateTimeZone_clone_basic3.phpt @@ -30,11 +30,19 @@ var_dump($d2_clone); *** Testing clone on DateTime objects *** -- Create a DateTimeZone object -- -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" } -- Add some properties -- -object(DateTimeZone)#%d (2) { +object(DateTimeZone)#%d (4) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" ["property1"]=> int(99) ["property2"]=> @@ -42,7 +50,11 @@ object(DateTimeZone)#%d (2) { } -- clone it -- -object(DateTimeZone)#%d (2) { +object(DateTimeZone)#%d (4) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" ["property1"]=> int(99) ["property2"]=> @@ -50,7 +62,11 @@ object(DateTimeZone)#%d (2) { } -- Add some more properties -- -object(DateTimeZone)#%d (4) { +object(DateTimeZone)#%d (6) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" ["property1"]=> int(99) ["property2"]=> @@ -62,7 +78,11 @@ object(DateTimeZone)#%d (4) { } -- clone it -- -object(DateTimeZone)#%d (4) { +object(DateTimeZone)#%d (6) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" ["property1"]=> int(99) ["property2"]=> diff --git a/ext/date/tests/DateTimeZone_construct_basic.phpt b/ext/date/tests/DateTimeZone_construct_basic.phpt index b681e8f9c3..2f18f81c03 100644 --- a/ext/date/tests/DateTimeZone_construct_basic.phpt +++ b/ext/date/tests/DateTimeZone_construct_basic.phpt @@ -21,10 +21,22 @@ var_dump( new DateTimeZone("America/Los_Angeles") ); ===DONE=== --EXPECTF-- *** Testing new DateTimeZone() : basic functionality *** -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" } -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" } -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(19) "America/Los_Angeles" } ===DONE=== diff --git a/ext/date/tests/DateTimeZone_serialize.phpt b/ext/date/tests/DateTimeZone_serialize.phpt index 08dd934466..49b9349bb8 100644 --- a/ext/date/tests/DateTimeZone_serialize.phpt +++ b/ext/date/tests/DateTimeZone_serialize.phpt @@ -18,12 +18,18 @@ var_dump( $tz2->getName() ); ?> ===DONE=== --EXPECTF-- -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(16) "America/New_York" } -string(24) "O:12:"DateTimeZone":0:{}" -object(DateTimeZone)#%d (0) { +string(88) "O:12:"DateTimeZone":2:{s:13:"timezone_type";i:3;s:8:"timezone";s:16:"America/New_York";}" +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(16) "America/New_York" } - -Warning: DateTimeZone::getName(): The DateTimeZone object has not been correctly initialized by its constructor in %s on line %d -bool(false) -===DONE=== \ No newline at end of file +string(16) "America/New_York" +===DONE=== diff --git a/ext/date/tests/DateTimeZone_verify.phpt b/ext/date/tests/DateTimeZone_verify.phpt index 3ca09131a7..1304000cc4 100644 --- a/ext/date/tests/DateTimeZone_verify.phpt +++ b/ext/date/tests/DateTimeZone_verify.phpt @@ -26,7 +26,7 @@ object(ReflectionClass)#%d (1) { string(12) "DateTimeZone" } ..and get names of all its methods -array(7) { +array(9) { [0]=> &object(ReflectionMethod)#%d (2) { ["name"]=> @@ -35,41 +35,55 @@ array(7) { string(12) "DateTimeZone" } [1]=> + &object(ReflectionMethod)#3 (2) { + ["name"]=> + string(8) "__wakeup" + ["class"]=> + string(12) "DateTimeZone" + } + [2]=> + &object(ReflectionMethod)#4 (2) { + ["name"]=> + string(11) "__set_state" + ["class"]=> + string(12) "DateTimeZone" + } + [3]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(7) "getName" ["class"]=> string(12) "DateTimeZone" } - [2]=> + [4]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(9) "getOffset" ["class"]=> string(12) "DateTimeZone" } - [3]=> + [5]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(14) "getTransitions" ["class"]=> string(12) "DateTimeZone" } - [4]=> + [6]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(11) "getLocation" ["class"]=> string(12) "DateTimeZone" } - [5]=> + [7]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(17) "listAbbreviations" ["class"]=> string(12) "DateTimeZone" } - [6]=> + [8]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(15) "listIdentifiers" diff --git a/ext/date/tests/timezone_open_basic1.phpt b/ext/date/tests/timezone_open_basic1.phpt index 7a989362b0..7fcfcb34cb 100644 --- a/ext/date/tests/timezone_open_basic1.phpt +++ b/ext/date/tests/timezone_open_basic1.phpt @@ -18,10 +18,22 @@ var_dump( timezone_open("America/Los_Angeles") ); ===DONE=== --EXPECTF-- *** Testing timezone_open() : basic functionality *** -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" } -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" } -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(19) "America/Los_Angeles" } ===DONE=== \ No newline at end of file -- cgit v1.2.1