Skip to content

Commit db826ee

Browse files
committed
Add DateTime/DateTimeImmutable's __serialize and __unserialize methods
1 parent a690a56 commit db826ee

11 files changed

+385
-33
lines changed

ext/date/php_date.c

Lines changed: 102 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1796,28 +1796,9 @@ static HashTable *date_object_get_gc_timezone(zend_object *object, zval **table,
17961796
return zend_std_get_properties(object);
17971797
} /* }}} */
17981798

1799-
static HashTable *date_object_get_properties_for(zend_object *object, zend_prop_purpose purpose) /* {{{ */
1799+
static void date_object_to_hash(php_date_obj *dateobj, HashTable *props)
18001800
{
1801-
HashTable *props;
18021801
zval zv;
1803-
php_date_obj *dateobj;
1804-
1805-
switch (purpose) {
1806-
case ZEND_PROP_PURPOSE_DEBUG:
1807-
case ZEND_PROP_PURPOSE_SERIALIZE:
1808-
case ZEND_PROP_PURPOSE_VAR_EXPORT:
1809-
case ZEND_PROP_PURPOSE_JSON:
1810-
case ZEND_PROP_PURPOSE_ARRAY_CAST:
1811-
break;
1812-
default:
1813-
return zend_std_get_properties_for(object, purpose);
1814-
}
1815-
1816-
dateobj = php_date_obj_from_obj(object);
1817-
props = zend_array_dup(zend_std_get_properties(object));
1818-
if (!dateobj->time) {
1819-
return props;
1820-
}
18211802

18221803
/* first we add the date and time in ISO format */
18231804
ZVAL_STR(&zv, date_format("Y-m-d H:i:s.u", sizeof("Y-m-d H:i:s.u")-1, dateobj->time, 1));
@@ -1850,6 +1831,31 @@ static HashTable *date_object_get_properties_for(zend_object *object, zend_prop_
18501831
}
18511832
zend_hash_str_update(props, "timezone", sizeof("timezone")-1, &zv);
18521833
}
1834+
}
1835+
1836+
static HashTable *date_object_get_properties_for(zend_object *object, zend_prop_purpose purpose) /* {{{ */
1837+
{
1838+
HashTable *props;
1839+
php_date_obj *dateobj;
1840+
1841+
switch (purpose) {
1842+
case ZEND_PROP_PURPOSE_DEBUG:
1843+
case ZEND_PROP_PURPOSE_SERIALIZE:
1844+
case ZEND_PROP_PURPOSE_VAR_EXPORT:
1845+
case ZEND_PROP_PURPOSE_JSON:
1846+
case ZEND_PROP_PURPOSE_ARRAY_CAST:
1847+
break;
1848+
default:
1849+
return zend_std_get_properties_for(object, purpose);
1850+
}
1851+
1852+
dateobj = php_date_obj_from_obj(object);
1853+
props = zend_array_dup(zend_std_get_properties(object));
1854+
if (!dateobj->time) {
1855+
return props;
1856+
}
1857+
1858+
date_object_to_hash(dateobj, props);
18531859

18541860
return props;
18551861
} /* }}} */
@@ -2605,6 +2611,82 @@ PHP_METHOD(DateTimeImmutable, __set_state)
26052611
}
26062612
/* }}} */
26072613

2614+
/* {{{ */
2615+
PHP_METHOD(DateTime, __serialize)
2616+
{
2617+
zval *object = ZEND_THIS;
2618+
php_date_obj *dateobj;
2619+
HashTable *myht;
2620+
2621+
ZEND_PARSE_PARAMETERS_NONE();
2622+
2623+
dateobj = Z_PHPDATE_P(object);
2624+
2625+
array_init(return_value);
2626+
myht = Z_ARRVAL_P(return_value);
2627+
date_object_to_hash(dateobj, myht);
2628+
}
2629+
/* }}} */
2630+
2631+
/* {{{ */
2632+
PHP_METHOD(DateTimeImmutable, __serialize)
2633+
{
2634+
zval *object = ZEND_THIS;
2635+
php_date_obj *dateobj;
2636+
HashTable *myht;
2637+
2638+
ZEND_PARSE_PARAMETERS_NONE();
2639+
2640+
dateobj = Z_PHPDATE_P(object);
2641+
2642+
array_init(return_value);
2643+
myht = Z_ARRVAL_P(return_value);
2644+
date_object_to_hash(dateobj, myht);
2645+
}
2646+
/* }}} */
2647+
2648+
/* {{{ */
2649+
PHP_METHOD(DateTime, __unserialize)
2650+
{
2651+
zval *object = ZEND_THIS;
2652+
php_date_obj *dateobj;
2653+
zval *array;
2654+
HashTable *myht;
2655+
2656+
ZEND_PARSE_PARAMETERS_START(1, 1)
2657+
Z_PARAM_ARRAY(array)
2658+
ZEND_PARSE_PARAMETERS_END();
2659+
2660+
dateobj = Z_PHPDATE_P(object);
2661+
myht = Z_ARRVAL_P(array);
2662+
2663+
if (!php_date_initialize_from_hash(&dateobj, myht)) {
2664+
zend_throw_error(NULL, "Invalid serialization data for DateTime object");
2665+
}
2666+
}
2667+
/* }}} */
2668+
2669+
/* {{{ */
2670+
PHP_METHOD(DateTimeImmutable, __unserialize)
2671+
{
2672+
zval *object = ZEND_THIS;
2673+
php_date_obj *dateobj;
2674+
zval *array;
2675+
HashTable *myht;
2676+
2677+
ZEND_PARSE_PARAMETERS_START(1, 1)
2678+
Z_PARAM_ARRAY(array)
2679+
ZEND_PARSE_PARAMETERS_END();
2680+
2681+
dateobj = Z_PHPDATE_P(object);
2682+
myht = Z_ARRVAL_P(array);
2683+
2684+
if (!php_date_initialize_from_hash(&dateobj, myht)) {
2685+
zend_throw_error(NULL, "Invalid serialization data for DateTimeImmutable object");
2686+
}
2687+
}
2688+
/* }}} */
2689+
26082690
/* {{{ */
26092691
PHP_METHOD(DateTime, __wakeup)
26102692
{

ext/date/php_date.stub.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,12 +205,20 @@ public function diff(DateTimeInterface $targetObject, bool $absolute = false): D
205205

206206
/** @tentative-return-type */
207207
public function __wakeup(): void;
208+
209+
public function __serialize(): array;
210+
211+
public function __unserialize(array $data): void;
208212
}
209213

210214
class DateTime implements DateTimeInterface
211215
{
212216
public function __construct(string $datetime = "now", ?DateTimeZone $timezone = null) {}
213217

218+
public function __serialize(): array {}
219+
220+
public function __unserialize(array $data): void {}
221+
214222
/** @tentative-return-type */
215223
public function __wakeup(): void {}
216224

@@ -318,6 +326,10 @@ class DateTimeImmutable implements DateTimeInterface
318326
{
319327
public function __construct(string $datetime = "now", ?DateTimeZone $timezone = null) {}
320328

329+
public function __serialize(): array {}
330+
331+
public function __unserialize(array $data): void {}
332+
321333
/** @tentative-return-type */
322334
public function __wakeup(): void {}
323335

ext/date/php_date_arginfo.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,11 +245,21 @@ ZEND_END_ARG_INFO()
245245
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_DateTimeInterface___wakeup, 0, 0, IS_VOID, 0)
246246
ZEND_END_ARG_INFO()
247247

248+
#define arginfo_class_DateTimeInterface___serialize arginfo_timezone_abbreviations_list
249+
250+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_DateTimeInterface___unserialize, 0, 1, IS_VOID, 0)
251+
ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0)
252+
ZEND_END_ARG_INFO()
253+
248254
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DateTime___construct, 0, 0, 0)
249255
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, datetime, IS_STRING, 0, "\"now\"")
250256
ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, timezone, DateTimeZone, 1, "null")
251257
ZEND_END_ARG_INFO()
252258

259+
#define arginfo_class_DateTime___serialize arginfo_timezone_abbreviations_list
260+
261+
#define arginfo_class_DateTime___unserialize arginfo_class_DateTimeInterface___unserialize
262+
253263
#define arginfo_class_DateTime___wakeup arginfo_class_DateTimeInterface___wakeup
254264

255265
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(arginfo_class_DateTime___set_state, 0, 1, DateTime, 0)
@@ -322,6 +332,10 @@ ZEND_END_ARG_INFO()
322332

323333
#define arginfo_class_DateTimeImmutable___construct arginfo_class_DateTime___construct
324334

335+
#define arginfo_class_DateTimeImmutable___serialize arginfo_timezone_abbreviations_list
336+
337+
#define arginfo_class_DateTimeImmutable___unserialize arginfo_class_DateTimeInterface___unserialize
338+
325339
#define arginfo_class_DateTimeImmutable___wakeup arginfo_class_DateTimeInterface___wakeup
326340

327341
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(arginfo_class_DateTimeImmutable___set_state, 0, 1, DateTimeImmutable, 0)
@@ -517,11 +531,15 @@ ZEND_FUNCTION(date_sunrise);
517531
ZEND_FUNCTION(date_sunset);
518532
ZEND_FUNCTION(date_sun_info);
519533
ZEND_METHOD(DateTime, __construct);
534+
ZEND_METHOD(DateTime, __serialize);
535+
ZEND_METHOD(DateTime, __unserialize);
520536
ZEND_METHOD(DateTime, __wakeup);
521537
ZEND_METHOD(DateTime, __set_state);
522538
ZEND_METHOD(DateTime, createFromImmutable);
523539
ZEND_METHOD(DateTime, createFromInterface);
524540
ZEND_METHOD(DateTimeImmutable, __construct);
541+
ZEND_METHOD(DateTimeImmutable, __serialize);
542+
ZEND_METHOD(DateTimeImmutable, __unserialize);
525543
ZEND_METHOD(DateTimeImmutable, __wakeup);
526544
ZEND_METHOD(DateTimeImmutable, __set_state);
527545
ZEND_METHOD(DateTimeImmutable, modify);
@@ -610,12 +628,16 @@ static const zend_function_entry class_DateTimeInterface_methods[] = {
610628
ZEND_ABSTRACT_ME_WITH_FLAGS(DateTimeInterface, getTimestamp, arginfo_class_DateTimeInterface_getTimestamp, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
611629
ZEND_ABSTRACT_ME_WITH_FLAGS(DateTimeInterface, diff, arginfo_class_DateTimeInterface_diff, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
612630
ZEND_ABSTRACT_ME_WITH_FLAGS(DateTimeInterface, __wakeup, arginfo_class_DateTimeInterface___wakeup, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
631+
ZEND_ABSTRACT_ME_WITH_FLAGS(DateTimeInterface, __serialize, arginfo_class_DateTimeInterface___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
632+
ZEND_ABSTRACT_ME_WITH_FLAGS(DateTimeInterface, __unserialize, arginfo_class_DateTimeInterface___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
613633
ZEND_FE_END
614634
};
615635

616636

617637
static const zend_function_entry class_DateTime_methods[] = {
618638
ZEND_ME(DateTime, __construct, arginfo_class_DateTime___construct, ZEND_ACC_PUBLIC)
639+
ZEND_ME(DateTime, __serialize, arginfo_class_DateTime___serialize, ZEND_ACC_PUBLIC)
640+
ZEND_ME(DateTime, __unserialize, arginfo_class_DateTime___unserialize, ZEND_ACC_PUBLIC)
619641
ZEND_ME(DateTime, __wakeup, arginfo_class_DateTime___wakeup, ZEND_ACC_PUBLIC)
620642
ZEND_ME(DateTime, __set_state, arginfo_class_DateTime___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
621643
ZEND_ME(DateTime, createFromImmutable, arginfo_class_DateTime_createFromImmutable, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
@@ -641,6 +663,8 @@ static const zend_function_entry class_DateTime_methods[] = {
641663

642664
static const zend_function_entry class_DateTimeImmutable_methods[] = {
643665
ZEND_ME(DateTimeImmutable, __construct, arginfo_class_DateTimeImmutable___construct, ZEND_ACC_PUBLIC)
666+
ZEND_ME(DateTimeImmutable, __serialize, arginfo_class_DateTimeImmutable___serialize, ZEND_ACC_PUBLIC)
667+
ZEND_ME(DateTimeImmutable, __unserialize, arginfo_class_DateTimeImmutable___unserialize, ZEND_ACC_PUBLIC)
644668
ZEND_ME(DateTimeImmutable, __wakeup, arginfo_class_DateTimeImmutable___wakeup, ZEND_ACC_PUBLIC)
645669
ZEND_ME(DateTimeImmutable, __set_state, arginfo_class_DateTimeImmutable___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
646670
ZEND_ME_MAPPING(createFromFormat, date_create_immutable_from_format, arginfo_class_DateTimeImmutable_createFromFormat, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
--TEST--
2+
Test DateTimeImmutable::__serialize and DateTimeImmutable::__unserialize
3+
--FILE--
4+
<?php
5+
//Set the default time zone
6+
date_default_timezone_set("Europe/London");
7+
8+
$d = new DateTimeImmutable("2022-04-14 11:27:42");
9+
echo "Original object:\n";
10+
var_dump($d);
11+
12+
echo "\n\nSerialised object:\n";
13+
$s = serialize($d);
14+
var_dump($s);
15+
16+
echo "\n\nUnserialised object:\n";
17+
$e = unserialize($s);
18+
var_dump($e);
19+
20+
echo "\n\nCalling __serialize manually:\n";
21+
var_dump($d->__serialize());
22+
23+
echo "\n\nCalling __unserialize manually:\n";
24+
$d = new DateTimeImmutable;
25+
$d->__unserialize(
26+
[
27+
'date' => '2022-04-14 11:27:42.541106',
28+
'timezone_type' => 3,
29+
'timezone' => 'UTC',
30+
]
31+
);
32+
var_dump($d);
33+
34+
echo "\n\nCalling __unserialize a few more times, with abbreviations:\n";
35+
$d->__unserialize(
36+
[
37+
'date' => '2022-04-14 11:27:42.541106',
38+
'timezone_type' => 2,
39+
'timezone' => 'CEST',
40+
]
41+
);
42+
var_dump($d);
43+
$d->__unserialize(
44+
[
45+
'date' => '2022-04-14 11:27:42.541106',
46+
'timezone_type' => 1,
47+
'timezone' => '+0130',
48+
]
49+
);
50+
var_dump($d);
51+
52+
?>
53+
--EXPECTF--
54+
Original object:
55+
object(DateTimeImmutable)#%d (%d) {
56+
["date"]=>
57+
string(26) "2022-04-14 11:27:42.000000"
58+
["timezone_type"]=>
59+
int(3)
60+
["timezone"]=>
61+
string(13) "Europe/London"
62+
}
63+
64+
65+
Serialised object:
66+
string(135) "O:17:"DateTimeImmutable":3:{s:4:"date";s:26:"2022-04-14 11:27:42.000000";s:13:"timezone_type";i:3;s:8:"timezone";s:13:"Europe/London";}"
67+
68+
69+
Unserialised object:
70+
object(DateTimeImmutable)#%d (%d) {
71+
["date"]=>
72+
string(26) "2022-04-14 11:27:42.000000"
73+
["timezone_type"]=>
74+
int(3)
75+
["timezone"]=>
76+
string(13) "Europe/London"
77+
}
78+
79+
80+
Calling __serialize manually:
81+
array(3) {
82+
["date"]=>
83+
string(26) "2022-04-14 11:27:42.000000"
84+
["timezone_type"]=>
85+
int(3)
86+
["timezone"]=>
87+
string(13) "Europe/London"
88+
}
89+
90+
91+
Calling __unserialize manually:
92+
object(DateTimeImmutable)#%d (%d) {
93+
["date"]=>
94+
string(26) "2022-04-14 11:27:42.541106"
95+
["timezone_type"]=>
96+
int(3)
97+
["timezone"]=>
98+
string(3) "UTC"
99+
}
100+
101+
102+
Calling __unserialize a few more times, with abbreviations:
103+
object(DateTimeImmutable)#%d (%d) {
104+
["date"]=>
105+
string(26) "2022-04-14 11:27:42.541106"
106+
["timezone_type"]=>
107+
int(2)
108+
["timezone"]=>
109+
string(4) "CEST"
110+
}
111+
object(DateTimeImmutable)#%d (%d) {
112+
["date"]=>
113+
string(26) "2022-04-14 11:27:42.541106"
114+
["timezone_type"]=>
115+
int(1)
116+
["timezone"]=>
117+
string(6) "+01:30"
118+
}

0 commit comments

Comments
 (0)