Skip to content

Commit 0715279

Browse files
committed
Declare DatePeriod properties
1 parent 97ea6ad commit 0715279

8 files changed

+181
-107
lines changed

ext/date/php_date.c

Lines changed: 89 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -172,19 +172,22 @@ static HashTable *date_object_get_properties_for(zend_object *object, zend_prop_
172172
static HashTable *date_object_get_gc_interval(zend_object *object, zval **table, int *n);
173173
static HashTable *date_object_get_properties_interval(zend_object *object);
174174
static HashTable *date_object_get_gc_period(zend_object *object, zval **table, int *n);
175-
static HashTable *date_object_get_properties_period(zend_object *object);
176175
static HashTable *date_object_get_properties_for_timezone(zend_object *object, zend_prop_purpose purpose);
177176
static HashTable *date_object_get_gc_timezone(zend_object *object, zval **table, int *n);
178177
static HashTable *date_object_get_debug_info_timezone(zend_object *object, int *is_temp);
179178
static void php_timezone_to_string(php_timezone_obj *tzobj, zval *zv);
180179

180+
static void create_date_period_datetime(timelib_time *datetime, zend_class_entry *ce, zval *zv);
181+
static void create_date_period_interval(timelib_rel_time *interval, zval *zv);
182+
static void initialize_date_period_properties(php_period_obj *period_obj);
183+
181184
static int date_interval_compare_objects(zval *o1, zval *o2);
182185
static zval *date_interval_read_property(zend_object *object, zend_string *member, int type, void **cache_slot, zval *rv);
183186
static zval *date_interval_write_property(zend_object *object, zend_string *member, zval *value, void **cache_slot);
184187
static zval *date_interval_get_property_ptr_ptr(zend_object *object, zend_string *member, int type, void **cache_slot);
188+
static zval *date_period_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot);
185189
static zval *date_period_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv);
186190
static zval *date_period_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot);
187-
static zval *date_period_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot);
188191

189192
static int date_object_compare_timezone(zval *tz1, zval *tz2);
190193

@@ -1521,10 +1524,21 @@ static void date_period_it_move_forward(zend_object_iterator *iter)
15211524
{
15221525
date_period_it *iterator = (date_period_it *)iter;
15231526
php_period_obj *object = Z_PHPPERIOD_P(&iterator->intern.data);
1524-
timelib_time *it_time = object->current;
1527+
timelib_time *it_time = object->current;
1528+
zval current_zv;
15251529

15261530
date_period_advance(it_time, object->interval);
15271531

1532+
if (UNEXPECTED(!object->std.properties)) {
1533+
rebuild_object_properties(&object->std);
1534+
}
1535+
1536+
create_date_period_datetime(object->current, object->start_ce, &current_zv);
1537+
zend_string *property_name = zend_string_init("current", sizeof("current") - 1, 0);
1538+
zend_std_write_property(&object->std, property_name, &current_zv, NULL);
1539+
zval_ptr_dtor(&current_zv);
1540+
zend_string_release(property_name);
1541+
15281542
iterator->current_index++;
15291543
date_period_it_invalidate_current(iter);
15301544
}
@@ -1722,9 +1736,8 @@ static void date_register_classes(void) /* {{{ */
17221736
date_object_handlers_period.offset = XtOffsetOf(php_period_obj, std);
17231737
date_object_handlers_period.free_obj = date_object_free_storage_period;
17241738
date_object_handlers_period.clone_obj = date_object_clone_period;
1725-
date_object_handlers_period.get_properties = date_object_get_properties_period;
1726-
date_object_handlers_period.get_property_ptr_ptr = date_period_get_property_ptr_ptr;
17271739
date_object_handlers_period.get_gc = date_object_get_gc_period;
1740+
date_object_handlers_period.get_property_ptr_ptr = date_period_get_property_ptr_ptr;
17281741
date_object_handlers_period.read_property = date_period_read_property;
17291742
date_object_handlers_period.write_property = date_period_write_property;
17301743

@@ -4564,6 +4577,8 @@ PHP_METHOD(DatePeriod, __construct)
45644577
dpobj->recurrences = recurrences + dpobj->include_start_date;
45654578

45664579
dpobj->initialized = 1;
4580+
4581+
initialize_date_period_properties(dpobj);
45674582
}
45684583
/* }}} */
45694584

@@ -5027,45 +5042,16 @@ static void date_period_object_to_hash(php_period_obj *period_obj, HashTable *pr
50275042
{
50285043
zval zv;
50295044

5030-
if (period_obj->start) {
5031-
php_date_obj *date_obj;
5032-
object_init_ex(&zv, period_obj->start_ce);
5033-
date_obj = Z_PHPDATE_P(&zv);
5034-
date_obj->time = timelib_time_clone(period_obj->start);
5035-
} else {
5036-
ZVAL_NULL(&zv);
5037-
}
5045+
create_date_period_datetime(period_obj->start, period_obj->start_ce, &zv);
50385046
zend_hash_str_update(props, "start", sizeof("start")-1, &zv);
50395047

5040-
if (period_obj->current) {
5041-
php_date_obj *date_obj;
5042-
object_init_ex(&zv, period_obj->start_ce);
5043-
date_obj = Z_PHPDATE_P(&zv);
5044-
date_obj->time = timelib_time_clone(period_obj->current);
5045-
} else {
5046-
ZVAL_NULL(&zv);
5047-
}
5048+
create_date_period_datetime(period_obj->current, period_obj->start_ce, &zv);
50485049
zend_hash_str_update(props, "current", sizeof("current")-1, &zv);
50495050

5050-
if (period_obj->end) {
5051-
php_date_obj *date_obj;
5052-
object_init_ex(&zv, period_obj->start_ce);
5053-
date_obj = Z_PHPDATE_P(&zv);
5054-
date_obj->time = timelib_time_clone(period_obj->end);
5055-
} else {
5056-
ZVAL_NULL(&zv);
5057-
}
5051+
create_date_period_datetime(period_obj->end, period_obj->start_ce, &zv);
50585052
zend_hash_str_update(props, "end", sizeof("end")-1, &zv);
50595053

5060-
if (period_obj->interval) {
5061-
php_interval_obj *interval_obj;
5062-
object_init_ex(&zv, date_ce_interval);
5063-
interval_obj = Z_PHPINTERVAL_P(&zv);
5064-
interval_obj->diff = timelib_rel_time_clone(period_obj->interval);
5065-
interval_obj->initialized = 1;
5066-
} else {
5067-
ZVAL_NULL(&zv);
5068-
}
5054+
create_date_period_interval(period_obj->interval, &zv);
50695055
zend_hash_str_update(props, "interval", sizeof("interval")-1, &zv);
50705056

50715057
/* converted to larger type (int->long); must check when unserializing */
@@ -5076,22 +5062,6 @@ static void date_period_object_to_hash(php_period_obj *period_obj, HashTable *pr
50765062
zend_hash_str_update(props, "include_start_date", sizeof("include_start_date")-1, &zv);
50775063
}
50785064

5079-
static HashTable *date_object_get_properties_period(zend_object *object) /* {{{ */
5080-
{
5081-
HashTable *props;
5082-
php_period_obj *period_obj;
5083-
5084-
period_obj = php_period_obj_from_obj(object);
5085-
props = zend_std_get_properties(object);
5086-
if (!period_obj->start) {
5087-
return props;
5088-
}
5089-
5090-
date_period_object_to_hash(period_obj, props);
5091-
5092-
return props;
5093-
} /* }}} */
5094-
50955065
static bool php_date_period_initialize_from_hash(php_period_obj *period_obj, HashTable *myht) /* {{{ */
50965066
{
50975067
zval *ht_entry;
@@ -5169,6 +5139,8 @@ static bool php_date_period_initialize_from_hash(php_period_obj *period_obj, Has
51695139

51705140
period_obj->initialized = 1;
51715141

5142+
initialize_date_period_properties(period_obj);
5143+
51725144
return 1;
51735145
} /* }}} */
51745146

@@ -5252,10 +5224,10 @@ PHP_METHOD(DatePeriod, __wakeup)
52525224
}
52535225
/* }}} */
52545226

5255-
/* {{{ date_period_is_magic_property
5227+
/* {{{ date_period_is_internal_property
52565228
* Common for date_period_read_property() and date_period_write_property() functions
52575229
*/
5258-
static bool date_period_is_magic_property(zend_string *name)
5230+
static bool date_period_is_internal_property(zend_string *name)
52595231
{
52605232
if (zend_string_equals_literal(name, "recurrences")
52615233
|| zend_string_equals_literal(name, "include_start_date")
@@ -5274,38 +5246,87 @@ static bool date_period_is_magic_property(zend_string *name)
52745246
static zval *date_period_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv)
52755247
{
52765248
if (type != BP_VAR_IS && type != BP_VAR_R) {
5277-
if (date_period_is_magic_property(name)) {
5278-
zend_throw_error(NULL, "Retrieval of DatePeriod->%s for modification is unsupported", ZSTR_VAL(name));
5249+
if (date_period_is_internal_property(name)) {
5250+
zend_throw_error(NULL, "Cannot modify readonly property DatePeriod::$%s", ZSTR_VAL(name));
52795251
return &EG(uninitialized_zval);
52805252
}
52815253
}
52825254

5283-
object->handlers->get_properties(object); /* build properties hash table */
5284-
52855255
return zend_std_read_property(object, name, type, cache_slot, rv);
52865256
}
52875257
/* }}} */
52885258

5289-
/* {{{ date_period_write_property */
52905259
static zval *date_period_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot)
52915260
{
5292-
if (date_period_is_magic_property(name)) {
5293-
zend_throw_error(NULL, "Writing to DatePeriod->%s is unsupported", ZSTR_VAL(name));
5261+
if (zend_string_equals_literal(name, "current")) {
5262+
zend_throw_error(NULL, "Cannot modify readonly property DatePeriod::$%s", ZSTR_VAL(name));
52945263
return value;
52955264
}
52965265

52975266
return zend_std_write_property(object, name, value, cache_slot);
52985267
}
5299-
/* }}} */
53005268

5301-
/* {{{ date_period_get_property_ptr_ptr */
53025269
static zval *date_period_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot)
53035270
{
5304-
if (date_period_is_magic_property(name)) {
5305-
zend_throw_error(NULL, "Retrieval of DatePeriod->%s for modification is unsupported", ZSTR_VAL(name));
5271+
if (zend_string_equals_literal(name, "current")) {
5272+
zend_throw_error(NULL, "Cannot modify readonly property DatePeriod::$%s", ZSTR_VAL(name));
53065273
return &EG(error_zval);
53075274
}
53085275

53095276
return zend_std_get_property_ptr_ptr(object, name, type, cache_slot);
53105277
}
5311-
/* }}} */
5278+
5279+
static void create_date_period_datetime(timelib_time *datetime, zend_class_entry *ce, zval *zv)
5280+
{
5281+
if (datetime) {
5282+
php_date_obj *date_obj;
5283+
object_init_ex(zv, ce);
5284+
date_obj = Z_PHPDATE_P(zv);
5285+
date_obj->time = timelib_time_clone(datetime);
5286+
} else {
5287+
ZVAL_NULL(zv);
5288+
}
5289+
}
5290+
5291+
static void create_date_period_interval(timelib_rel_time *interval, zval *zv)
5292+
{
5293+
if (interval) {
5294+
php_interval_obj *interval_obj;
5295+
object_init_ex(zv, date_ce_interval);
5296+
interval_obj = Z_PHPINTERVAL_P(zv);
5297+
interval_obj->diff = timelib_rel_time_clone(interval);
5298+
interval_obj->initialized = 1;
5299+
} else {
5300+
ZVAL_NULL(zv);
5301+
}
5302+
}
5303+
5304+
static void initialize_date_period_properties(php_period_obj *period_obj)
5305+
{
5306+
zval start_zv, current_zv, end_zv, interval_zv;
5307+
5308+
if (UNEXPECTED(!period_obj->std.properties)) {
5309+
rebuild_object_properties(&period_obj->std);
5310+
}
5311+
5312+
create_date_period_datetime(period_obj->start, period_obj->start_ce, &start_zv);
5313+
zend_update_property(date_ce_period, &period_obj->std, "start", sizeof("start") - 1, &start_zv);
5314+
zval_ptr_dtor(&start_zv);
5315+
5316+
create_date_period_datetime(period_obj->current, period_obj->start_ce, &current_zv);
5317+
zend_string *property_name = zend_string_init("current", sizeof("current") - 1, 0);
5318+
zend_std_write_property(&period_obj->std, property_name, &current_zv, NULL);
5319+
zval_ptr_dtor(&current_zv);
5320+
zend_string_release(property_name);
5321+
5322+
create_date_period_datetime(period_obj->end, period_obj->start_ce, &end_zv);
5323+
zend_update_property(date_ce_period, &period_obj->std, "end", sizeof("end") - 1, &end_zv);
5324+
zval_ptr_dtor(&end_zv);
5325+
5326+
create_date_period_interval(period_obj->interval, &interval_zv);
5327+
zend_update_property(date_ce_period, &period_obj->std, "interval", sizeof("interval") - 1, &interval_zv);
5328+
zval_ptr_dtor(&interval_zv);
5329+
5330+
zend_update_property_long(date_ce_period, &period_obj->std, "recurrences", sizeof("recurrences") - 1, (zend_long) period_obj->recurrences);
5331+
zend_update_property_bool(date_ce_period, &period_obj->std, "include_start_date", sizeof("include_start_date") - 1, period_obj->include_start_date);
5332+
}

ext/date/php_date.stub.php

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

494494
class DatePeriod implements IteratorAggregate
495495
{
496+
public readonly ?DateTimeInterface $start;
497+
public ?DateTimeInterface $current;
498+
public readonly ?DateTimeInterface $end;
499+
public readonly ?DateInterval $interval;
500+
public readonly int $recurrences;
501+
public readonly bool $include_start_date;
502+
496503
/**
497504
* @param DateTimeInterface|string $start
498505
* @param DateInterval|int $interval

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: db6fd5b6c366dd8ee48ead99d235baa86e564401 */
2+
* Stub hash: 0073cb262ba1b9b5bcf211242c5ba1be9386ade9 */
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)
@@ -808,5 +808,45 @@ static zend_class_entry *register_class_DatePeriod(zend_class_entry *class_entry
808808
class_entry = zend_register_internal_class_ex(&ce, NULL);
809809
zend_class_implements(class_entry, 1, class_entry_IteratorAggregate);
810810

811+
zend_string *property_start_class_DateTimeInterface = zend_string_init("DateTimeInterface", sizeof("DateTimeInterface")-1, 1);
812+
zval property_start_default_value;
813+
ZVAL_UNDEF(&property_start_default_value);
814+
zend_string *property_start_name = zend_string_init("start", sizeof("start") - 1, 1);
815+
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));
816+
zend_string_release(property_start_name);
817+
818+
zend_string *property_current_class_DateTimeInterface = zend_string_init("DateTimeInterface", sizeof("DateTimeInterface")-1, 1);
819+
zval property_current_default_value;
820+
ZVAL_UNDEF(&property_current_default_value);
821+
zend_string *property_current_name = zend_string_init("current", sizeof("current") - 1, 1);
822+
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));
823+
zend_string_release(property_current_name);
824+
825+
zend_string *property_end_class_DateTimeInterface = zend_string_init("DateTimeInterface", sizeof("DateTimeInterface")-1, 1);
826+
zval property_end_default_value;
827+
ZVAL_UNDEF(&property_end_default_value);
828+
zend_string *property_end_name = zend_string_init("end", sizeof("end") - 1, 1);
829+
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));
830+
zend_string_release(property_end_name);
831+
832+
zend_string *property_interval_class_DateInterval = zend_string_init("DateInterval", sizeof("DateInterval")-1, 1);
833+
zval property_interval_default_value;
834+
ZVAL_UNDEF(&property_interval_default_value);
835+
zend_string *property_interval_name = zend_string_init("interval", sizeof("interval") - 1, 1);
836+
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));
837+
zend_string_release(property_interval_name);
838+
839+
zval property_recurrences_default_value;
840+
ZVAL_UNDEF(&property_recurrences_default_value);
841+
zend_string *property_recurrences_name = zend_string_init("recurrences", sizeof("recurrences") - 1, 1);
842+
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));
843+
zend_string_release(property_recurrences_name);
844+
845+
zval property_include_start_date_default_value;
846+
ZVAL_UNDEF(&property_include_start_date_default_value);
847+
zend_string *property_include_start_date_name = zend_string_init("include_start_date", sizeof("include_start_date") - 1, 1);
848+
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));
849+
zend_string_release(property_include_start_date_name);
850+
811851
return class_entry;
812852
}

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)