Skip to content

Commit 94cec42

Browse files
committed
Declare DatePeriod properties
1 parent 9f06bb3 commit 94cec42

File tree

4 files changed

+155
-81
lines changed

4 files changed

+155
-81
lines changed

ext/date/php_date.c

Lines changed: 89 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -299,19 +299,22 @@ static HashTable *date_object_get_properties_for(zend_object *object, zend_prop_
299299
static HashTable *date_object_get_gc_interval(zend_object *object, zval **table, int *n);
300300
static HashTable *date_object_get_properties_interval(zend_object *object);
301301
static HashTable *date_object_get_gc_period(zend_object *object, zval **table, int *n);
302-
static HashTable *date_object_get_properties_period(zend_object *object);
303302
static HashTable *date_object_get_properties_for_timezone(zend_object *object, zend_prop_purpose purpose);
304303
static HashTable *date_object_get_gc_timezone(zend_object *object, zval **table, int *n);
305304
static HashTable *date_object_get_debug_info_timezone(zend_object *object, int *is_temp);
306305
static void php_timezone_to_string(php_timezone_obj *tzobj, zval *zv);
307306

307+
static void create_date_period_datetime(timelib_time *datetime, zend_class_entry *ce, zval *zv);
308+
static void create_date_period_interval(timelib_rel_time *interval, zval *zv);
309+
static void initialize_date_period_properties(php_period_obj *period_obj);
310+
308311
static int date_interval_compare_objects(zval *o1, zval *o2);
309312
static zval *date_interval_read_property(zend_object *object, zend_string *member, int type, void **cache_slot, zval *rv);
310313
static zval *date_interval_write_property(zend_object *object, zend_string *member, zval *value, void **cache_slot);
311314
static zval *date_interval_get_property_ptr_ptr(zend_object *object, zend_string *member, int type, void **cache_slot);
315+
static zval *date_period_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot);
312316
static zval *date_period_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv);
313317
static zval *date_period_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot);
314-
static zval *date_period_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot);
315318

316319
static int date_object_compare_timezone(zval *tz1, zval *tz2);
317320

@@ -1491,10 +1494,21 @@ static void date_period_it_move_forward(zend_object_iterator *iter)
14911494
{
14921495
date_period_it *iterator = (date_period_it *)iter;
14931496
php_period_obj *object = Z_PHPPERIOD_P(&iterator->intern.data);
1494-
timelib_time *it_time = object->current;
1497+
timelib_time *it_time = object->current;
1498+
zval current_zv;
14951499

14961500
date_period_advance(it_time, object->interval);
14971501

1502+
if (UNEXPECTED(!object->std.properties)) {
1503+
rebuild_object_properties(&object->std);
1504+
}
1505+
1506+
create_date_period_datetime(object->current, object->start_ce, &current_zv);
1507+
zend_string *property_name = zend_string_init("current", sizeof("current") - 1, 0);
1508+
zend_std_write_property(&object->std, property_name, &current_zv, NULL);
1509+
zval_ptr_dtor(&current_zv);
1510+
zend_string_release(property_name);
1511+
14981512
iterator->current_index++;
14991513
date_period_it_invalidate_current(iter);
15001514
}
@@ -1657,9 +1671,8 @@ static void date_register_classes(void) /* {{{ */
16571671
date_object_handlers_period.offset = XtOffsetOf(php_period_obj, std);
16581672
date_object_handlers_period.free_obj = date_object_free_storage_period;
16591673
date_object_handlers_period.clone_obj = date_object_clone_period;
1660-
date_object_handlers_period.get_properties = date_object_get_properties_period;
1661-
date_object_handlers_period.get_property_ptr_ptr = date_period_get_property_ptr_ptr;
16621674
date_object_handlers_period.get_gc = date_object_get_gc_period;
1675+
date_object_handlers_period.get_property_ptr_ptr = date_period_get_property_ptr_ptr;
16631676
date_object_handlers_period.read_property = date_period_read_property;
16641677
date_object_handlers_period.write_property = date_period_write_property;
16651678
} /* }}} */
@@ -4502,6 +4515,8 @@ PHP_METHOD(DatePeriod, __construct)
45024515
dpobj->recurrences = recurrences + dpobj->include_start_date + dpobj->include_end_date;
45034516

45044517
dpobj->initialized = 1;
4518+
4519+
initialize_date_period_properties(dpobj);
45054520
}
45064521
/* }}} */
45074522

@@ -4965,45 +4980,16 @@ static void date_period_object_to_hash(php_period_obj *period_obj, HashTable *pr
49654980
{
49664981
zval zv;
49674982

4968-
if (period_obj->start) {
4969-
php_date_obj *date_obj;
4970-
object_init_ex(&zv, period_obj->start_ce);
4971-
date_obj = Z_PHPDATE_P(&zv);
4972-
date_obj->time = timelib_time_clone(period_obj->start);
4973-
} else {
4974-
ZVAL_NULL(&zv);
4975-
}
4983+
create_date_period_datetime(period_obj->start, period_obj->start_ce, &zv);
49764984
zend_hash_str_update(props, "start", sizeof("start")-1, &zv);
49774985

4978-
if (period_obj->current) {
4979-
php_date_obj *date_obj;
4980-
object_init_ex(&zv, period_obj->start_ce);
4981-
date_obj = Z_PHPDATE_P(&zv);
4982-
date_obj->time = timelib_time_clone(period_obj->current);
4983-
} else {
4984-
ZVAL_NULL(&zv);
4985-
}
4986+
create_date_period_datetime(period_obj->current, period_obj->start_ce, &zv);
49864987
zend_hash_str_update(props, "current", sizeof("current")-1, &zv);
49874988

4988-
if (period_obj->end) {
4989-
php_date_obj *date_obj;
4990-
object_init_ex(&zv, period_obj->start_ce);
4991-
date_obj = Z_PHPDATE_P(&zv);
4992-
date_obj->time = timelib_time_clone(period_obj->end);
4993-
} else {
4994-
ZVAL_NULL(&zv);
4995-
}
4989+
create_date_period_datetime(period_obj->end, period_obj->start_ce, &zv);
49964990
zend_hash_str_update(props, "end", sizeof("end")-1, &zv);
49974991

4998-
if (period_obj->interval) {
4999-
php_interval_obj *interval_obj;
5000-
object_init_ex(&zv, date_ce_interval);
5001-
interval_obj = Z_PHPINTERVAL_P(&zv);
5002-
interval_obj->diff = timelib_rel_time_clone(period_obj->interval);
5003-
interval_obj->initialized = 1;
5004-
} else {
5005-
ZVAL_NULL(&zv);
5006-
}
4992+
create_date_period_interval(period_obj->interval, &zv);
50074993
zend_hash_str_update(props, "interval", sizeof("interval")-1, &zv);
50084994

50094995
/* converted to larger type (int->long); must check when unserializing */
@@ -5017,22 +5003,6 @@ static void date_period_object_to_hash(php_period_obj *period_obj, HashTable *pr
50175003
zend_hash_str_update(props, "include_end_date", sizeof("include_end_date")-1, &zv);
50185004
}
50195005

5020-
static HashTable *date_object_get_properties_period(zend_object *object) /* {{{ */
5021-
{
5022-
HashTable *props;
5023-
php_period_obj *period_obj;
5024-
5025-
period_obj = php_period_obj_from_obj(object);
5026-
props = zend_std_get_properties(object);
5027-
if (!period_obj->start) {
5028-
return props;
5029-
}
5030-
5031-
date_period_object_to_hash(period_obj, props);
5032-
5033-
return props;
5034-
} /* }}} */
5035-
50365006
static bool php_date_period_initialize_from_hash(php_period_obj *period_obj, HashTable *myht) /* {{{ */
50375007
{
50385008
zval *ht_entry;
@@ -5118,6 +5088,8 @@ static bool php_date_period_initialize_from_hash(php_period_obj *period_obj, Has
51185088

51195089
period_obj->initialized = 1;
51205090

5091+
initialize_date_period_properties(period_obj);
5092+
51215093
return 1;
51225094
} /* }}} */
51235095

@@ -5201,10 +5173,10 @@ PHP_METHOD(DatePeriod, __wakeup)
52015173
}
52025174
/* }}} */
52035175

5204-
/* {{{ date_period_is_magic_property
5176+
/* {{{ date_period_is_internal_property
52055177
* Common for date_period_read_property() and date_period_write_property() functions
52065178
*/
5207-
static bool date_period_is_magic_property(zend_string *name)
5179+
static bool date_period_is_internal_property(zend_string *name)
52085180
{
52095181
if (zend_string_equals_literal(name, "recurrences")
52105182
|| zend_string_equals_literal(name, "include_start_date")
@@ -5224,38 +5196,87 @@ static bool date_period_is_magic_property(zend_string *name)
52245196
static zval *date_period_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv)
52255197
{
52265198
if (type != BP_VAR_IS && type != BP_VAR_R) {
5227-
if (date_period_is_magic_property(name)) {
5228-
zend_throw_error(NULL, "Retrieval of DatePeriod->%s for modification is unsupported", ZSTR_VAL(name));
5199+
if (date_period_is_internal_property(name)) {
5200+
zend_throw_error(NULL, "Cannot modify readonly property DatePeriod::$%s", ZSTR_VAL(name));
52295201
return &EG(uninitialized_zval);
52305202
}
52315203
}
52325204

5233-
object->handlers->get_properties(object); /* build properties hash table */
5234-
52355205
return zend_std_read_property(object, name, type, cache_slot, rv);
52365206
}
52375207
/* }}} */
52385208

5239-
/* {{{ date_period_write_property */
52405209
static zval *date_period_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot)
52415210
{
5242-
if (date_period_is_magic_property(name)) {
5243-
zend_throw_error(NULL, "Writing to DatePeriod->%s is unsupported", ZSTR_VAL(name));
5211+
if (zend_string_equals_literal(name, "current")) {
5212+
zend_throw_error(NULL, "Cannot modify readonly property DatePeriod::$%s", ZSTR_VAL(name));
52445213
return value;
52455214
}
52465215

52475216
return zend_std_write_property(object, name, value, cache_slot);
52485217
}
5249-
/* }}} */
52505218

5251-
/* {{{ date_period_get_property_ptr_ptr */
52525219
static zval *date_period_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot)
52535220
{
5254-
if (date_period_is_magic_property(name)) {
5255-
zend_throw_error(NULL, "Retrieval of DatePeriod->%s for modification is unsupported", ZSTR_VAL(name));
5221+
if (zend_string_equals_literal(name, "current")) {
5222+
zend_throw_error(NULL, "Cannot modify readonly property DatePeriod::$%s", ZSTR_VAL(name));
52565223
return &EG(error_zval);
52575224
}
52585225

52595226
return zend_std_get_property_ptr_ptr(object, name, type, cache_slot);
52605227
}
5261-
/* }}} */
5228+
5229+
static void create_date_period_datetime(timelib_time *datetime, zend_class_entry *ce, zval *zv)
5230+
{
5231+
if (datetime) {
5232+
php_date_obj *date_obj;
5233+
object_init_ex(zv, ce);
5234+
date_obj = Z_PHPDATE_P(zv);
5235+
date_obj->time = timelib_time_clone(datetime);
5236+
} else {
5237+
ZVAL_NULL(zv);
5238+
}
5239+
}
5240+
5241+
static void create_date_period_interval(timelib_rel_time *interval, zval *zv)
5242+
{
5243+
if (interval) {
5244+
php_interval_obj *interval_obj;
5245+
object_init_ex(zv, date_ce_interval);
5246+
interval_obj = Z_PHPINTERVAL_P(zv);
5247+
interval_obj->diff = timelib_rel_time_clone(interval);
5248+
interval_obj->initialized = 1;
5249+
} else {
5250+
ZVAL_NULL(zv);
5251+
}
5252+
}
5253+
5254+
static void initialize_date_period_properties(php_period_obj *period_obj)
5255+
{
5256+
zval start_zv, current_zv, end_zv, interval_zv;
5257+
5258+
if (UNEXPECTED(!period_obj->std.properties)) {
5259+
rebuild_object_properties(&period_obj->std);
5260+
}
5261+
5262+
create_date_period_datetime(period_obj->start, period_obj->start_ce, &start_zv);
5263+
zend_update_property(date_ce_period, &period_obj->std, "start", sizeof("start") - 1, &start_zv);
5264+
zval_ptr_dtor(&start_zv);
5265+
5266+
create_date_period_datetime(period_obj->current, period_obj->start_ce, &current_zv);
5267+
zend_string *property_name = zend_string_init("current", sizeof("current") - 1, 0);
5268+
zend_std_write_property(&period_obj->std, property_name, &current_zv, NULL);
5269+
zval_ptr_dtor(&current_zv);
5270+
zend_string_release(property_name);
5271+
5272+
create_date_period_datetime(period_obj->end, period_obj->start_ce, &end_zv);
5273+
zend_update_property(date_ce_period, &period_obj->std, "end", sizeof("end") - 1, &end_zv);
5274+
zval_ptr_dtor(&end_zv);
5275+
5276+
create_date_period_interval(period_obj->interval, &interval_zv);
5277+
zend_update_property(date_ce_period, &period_obj->std, "interval", sizeof("interval") - 1, &interval_zv);
5278+
zval_ptr_dtor(&interval_zv);
5279+
5280+
zend_update_property_long(date_ce_period, &period_obj->std, "recurrences", sizeof("recurrences") - 1, (zend_long) period_obj->recurrences);
5281+
zend_update_property_bool(date_ce_period, &period_obj->std, "include_start_date", sizeof("include_start_date") - 1, period_obj->include_start_date);
5282+
}

ext/date/php_date.stub.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,13 @@ public static function __set_state(array $array): DateInterval {}
683683

684684
class DatePeriod implements IteratorAggregate
685685
{
686+
public readonly ?DateTimeInterface $start;
687+
public ?DateTimeInterface $current;
688+
public readonly ?DateTimeInterface $end;
689+
public readonly ?DateInterval $interval;
690+
public readonly int $recurrences;
691+
public readonly bool $include_start_date;
692+
686693
/**
687694
* @var int
688695
* @cname PHP_DATE_PERIOD_EXCLUDE_START_DATE

ext/date/php_date_arginfo.h

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: 2cdf90d626d020b7e746cbccdb87833720d87132 */
2+
* Stub hash: d5f960d58c9577c755164d4372a2f4d70a3b1aaf */
33

44
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_strtotime, 0, 1, MAY_BE_LONG|MAY_BE_FALSE)
55
ZEND_ARG_TYPE_INFO(0, datetime, IS_STRING, 0)
@@ -1026,5 +1026,45 @@ static zend_class_entry *register_class_DatePeriod(zend_class_entry *class_entry
10261026
zend_declare_class_constant_ex(class_entry, const_INCLUDE_END_DATE_name, &const_INCLUDE_END_DATE_value, ZEND_ACC_PUBLIC, NULL);
10271027
zend_string_release(const_INCLUDE_END_DATE_name);
10281028

1029+
zend_string *property_start_class_DateTimeInterface = zend_string_init("DateTimeInterface", sizeof("DateTimeInterface")-1, 1);
1030+
zval property_start_default_value;
1031+
ZVAL_UNDEF(&property_start_default_value);
1032+
zend_string *property_start_name = zend_string_init("start", sizeof("start") - 1, 1);
1033+
zend_declare_typed_property(class_entry, property_start_name, &property_start_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_start_class_DateTimeInterface, 0, MAY_BE_NULL));
1034+
zend_string_release(property_start_name);
1035+
1036+
zend_string *property_current_class_DateTimeInterface = zend_string_init("DateTimeInterface", sizeof("DateTimeInterface")-1, 1);
1037+
zval property_current_default_value;
1038+
ZVAL_UNDEF(&property_current_default_value);
1039+
zend_string *property_current_name = zend_string_init("current", sizeof("current") - 1, 1);
1040+
zend_declare_typed_property(class_entry, property_current_name, &property_current_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_current_class_DateTimeInterface, 0, MAY_BE_NULL));
1041+
zend_string_release(property_current_name);
1042+
1043+
zend_string *property_end_class_DateTimeInterface = zend_string_init("DateTimeInterface", sizeof("DateTimeInterface")-1, 1);
1044+
zval property_end_default_value;
1045+
ZVAL_UNDEF(&property_end_default_value);
1046+
zend_string *property_end_name = zend_string_init("end", sizeof("end") - 1, 1);
1047+
zend_declare_typed_property(class_entry, property_end_name, &property_end_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_end_class_DateTimeInterface, 0, MAY_BE_NULL));
1048+
zend_string_release(property_end_name);
1049+
1050+
zend_string *property_interval_class_DateInterval = zend_string_init("DateInterval", sizeof("DateInterval")-1, 1);
1051+
zval property_interval_default_value;
1052+
ZVAL_UNDEF(&property_interval_default_value);
1053+
zend_string *property_interval_name = zend_string_init("interval", sizeof("interval") - 1, 1);
1054+
zend_declare_typed_property(class_entry, property_interval_name, &property_interval_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_interval_class_DateInterval, 0, MAY_BE_NULL));
1055+
zend_string_release(property_interval_name);
1056+
1057+
zval property_recurrences_default_value;
1058+
ZVAL_UNDEF(&property_recurrences_default_value);
1059+
zend_string *property_recurrences_name = zend_string_init("recurrences", sizeof("recurrences") - 1, 1);
1060+
zend_declare_typed_property(class_entry, property_recurrences_name, &property_recurrences_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
1061+
zend_string_release(property_recurrences_name);
1062+
1063+
zval property_include_start_date_default_value;
1064+
ZVAL_UNDEF(&property_include_start_date_default_value);
1065+
zend_string *property_include_start_date_name = zend_string_init("include_start_date", sizeof("include_start_date") - 1, 1);
1066+
zend_declare_typed_property(class_entry, property_include_start_date_name, &property_include_start_date_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
1067+
zend_string_release(property_include_start_date_name);
1068+
10291069
return class_entry;
10301070
}

ext/date/tests/DatePeriod_properties2.phpt

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,23 @@ foreach ($properties as $property) {
3030
}
3131
}
3232

33+
try {
34+
$period->start->modify("+1 hour");
35+
} catch (Error $e) {
36+
echo $e->getMessage() . "\n";
37+
}
38+
3339
?>
3440
--EXPECT--
35-
Writing to DatePeriod->recurrences is unsupported
36-
Retrieval of DatePeriod->recurrences for modification is unsupported
37-
Writing to DatePeriod->include_start_date is unsupported
38-
Retrieval of DatePeriod->include_start_date for modification is unsupported
39-
Writing to DatePeriod->start is unsupported
40-
Retrieval of DatePeriod->start for modification is unsupported
41-
Writing to DatePeriod->current is unsupported
42-
Retrieval of DatePeriod->current for modification is unsupported
43-
Writing to DatePeriod->end is unsupported
44-
Retrieval of DatePeriod->end for modification is unsupported
45-
Writing to DatePeriod->interval is unsupported
46-
Retrieval of DatePeriod->interval for modification is unsupported
41+
Cannot modify readonly property DatePeriod::$recurrences
42+
Cannot modify readonly property DatePeriod::$recurrences
43+
Cannot modify readonly property DatePeriod::$include_start_date
44+
Cannot modify readonly property DatePeriod::$include_start_date
45+
Cannot modify readonly property DatePeriod::$start
46+
Cannot modify readonly property DatePeriod::$start
47+
Cannot modify readonly property DatePeriod::$current
48+
Cannot modify readonly property DatePeriod::$current
49+
Cannot modify readonly property DatePeriod::$end
50+
Cannot modify readonly property DatePeriod::$end
51+
Cannot modify readonly property DatePeriod::$interval
52+
Cannot modify readonly property DatePeriod::$interval

0 commit comments

Comments
 (0)