Bug 54567 DateTimeZone serialize/unserialize

Make DateTimeZone serializable and implement __set_state
This commit is contained in:
Lonny Kapelushnik 2012-09-28 12:15:20 +00:00 committed by Derick Rethans
parent 5dd73b9e54
commit 30d0ae42b5
10 changed files with 243 additions and 33 deletions

View File

@ -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.
*/

View File

@ -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 {

View File

@ -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

View File

@ -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===

View File

@ -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===

View File

@ -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"]=>

View File

@ -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===

View File

@ -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===
string(16) "America/New_York"
===DONE===

View File

@ -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)#%d (2) {
&object(ReflectionMethod)#3 (2) {
["name"]=>
string(7) "getName"
string(8) "__wakeup"
["class"]=>
string(12) "DateTimeZone"
}
[2]=>
&object(ReflectionMethod)#%d (2) {
&object(ReflectionMethod)#4 (2) {
["name"]=>
string(9) "getOffset"
string(11) "__set_state"
["class"]=>
string(12) "DateTimeZone"
}
[3]=>
&object(ReflectionMethod)#%d (2) {
["name"]=>
string(14) "getTransitions"
string(7) "getName"
["class"]=>
string(12) "DateTimeZone"
}
[4]=>
&object(ReflectionMethod)#%d (2) {
["name"]=>
string(11) "getLocation"
string(9) "getOffset"
["class"]=>
string(12) "DateTimeZone"
}
[5]=>
&object(ReflectionMethod)#%d (2) {
["name"]=>
string(17) "listAbbreviations"
string(14) "getTransitions"
["class"]=>
string(12) "DateTimeZone"
}
[6]=>
&object(ReflectionMethod)#%d (2) {
["name"]=>
string(11) "getLocation"
["class"]=>
string(12) "DateTimeZone"
}
[7]=>
&object(ReflectionMethod)#%d (2) {
["name"]=>
string(17) "listAbbreviations"
["class"]=>
string(12) "DateTimeZone"
}
[8]=>
&object(ReflectionMethod)#%d (2) {
["name"]=>
string(15) "listIdentifiers"

View File

@ -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===