Skip to content

Commit 9144b30

Browse files
committed
Reduce memory overhead of DatePeriod via virtual properties
Related to #11644 and #13988
1 parent 8487ddb commit 9144b30

File tree

4 files changed

+97
-62
lines changed

4 files changed

+97
-62
lines changed

UPGRADING

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,6 +1074,9 @@ PHP 8.4 UPGRADE NOTES
10741074
of functions as well as serialization functions such as `json_encode()`,
10751075
`serialize()`.
10761076

1077+
- Date:
1078+
. Reduced memory usage of DatePeriod.
1079+
10771080
- DOM:
10781081
. The performance of DOMNode::C14N() is greatly improved for the case without
10791082
an xpath query. This can give a time improvement of easily two order of

ext/date/php_date.c

Lines changed: 58 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ static zval *date_interval_get_property_ptr_ptr(zend_object *object, zend_string
362362
static zval *date_period_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv);
363363
static zval *date_period_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot);
364364
static zval *date_period_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot);
365-
365+
static HashTable *date_period_get_properties_for(zend_object *object, zend_prop_purpose purpose);
366366
static int date_object_compare_timezone(zval *tz1, zval *tz2);
367367

368368
/* {{{ Module struct */
@@ -1501,45 +1501,6 @@ static void create_date_period_interval(timelib_rel_time *interval, zval *zv)
15011501
}
15021502
}
15031503

1504-
static void write_date_period_property(zend_object *obj, const char *name, const size_t name_len, zval *zv)
1505-
{
1506-
zend_string *property_name = zend_string_init(name, name_len, 0);
1507-
1508-
zend_std_write_property(obj, property_name, zv, NULL);
1509-
1510-
zval_ptr_dtor(zv);
1511-
zend_string_release(property_name);
1512-
}
1513-
1514-
static void initialize_date_period_properties(php_period_obj *period_obj)
1515-
{
1516-
zval zv;
1517-
1518-
/* rebuild properties */
1519-
zend_std_get_properties_ex(&period_obj->std);
1520-
1521-
create_date_period_datetime(period_obj->start, period_obj->start_ce, &zv);
1522-
write_date_period_property(&period_obj->std, "start", sizeof("start") - 1, &zv);
1523-
1524-
create_date_period_datetime(period_obj->current, period_obj->start_ce, &zv);
1525-
write_date_period_property(&period_obj->std, "current", sizeof("current") - 1, &zv);
1526-
1527-
create_date_period_datetime(period_obj->end, period_obj->start_ce, &zv);
1528-
write_date_period_property(&period_obj->std, "end", sizeof("end") - 1, &zv);
1529-
1530-
create_date_period_interval(period_obj->interval, &zv);
1531-
write_date_period_property(&period_obj->std, "interval", sizeof("interval") - 1, &zv);
1532-
1533-
ZVAL_LONG(&zv, (zend_long) period_obj->recurrences);
1534-
write_date_period_property(&period_obj->std, "recurrences", sizeof("recurrences") - 1, &zv);
1535-
1536-
ZVAL_BOOL(&zv, period_obj->include_start_date);
1537-
write_date_period_property(&period_obj->std, "include_start_date", sizeof("include_start_date") - 1, &zv);
1538-
1539-
ZVAL_BOOL(&zv, period_obj->include_end_date);
1540-
write_date_period_property(&period_obj->std, "include_end_date", sizeof("include_end_date") - 1, &zv);
1541-
}
1542-
15431504
/* define an overloaded iterator structure */
15441505
typedef struct {
15451506
zend_object_iterator intern;
@@ -1659,10 +1620,7 @@ static void date_period_it_move_forward(zend_object_iterator *iter)
16591620
zend_std_get_properties_ex(&object->std);
16601621

16611622
create_date_period_datetime(object->current, object->start_ce, &current_zv);
1662-
zend_string *property_name = ZSTR_INIT_LITERAL("current", 0);
1663-
zend_std_write_property(&object->std, property_name, &current_zv, NULL);
16641623
zval_ptr_dtor(&current_zv);
1665-
zend_string_release(property_name);
16661624

16671625
iterator->current_index++;
16681626
date_period_it_invalidate_current(iter);
@@ -1835,6 +1793,7 @@ static void date_register_classes(void) /* {{{ */
18351793
date_object_handlers_period.get_property_ptr_ptr = date_period_get_property_ptr_ptr;
18361794
date_object_handlers_period.read_property = date_period_read_property;
18371795
date_object_handlers_period.write_property = date_period_write_property;
1796+
date_object_handlers_period.get_properties_for = date_period_get_properties_for;
18381797

18391798
date_ce_date_error = register_class_DateError(zend_ce_error);
18401799
date_ce_date_object_error = register_class_DateObjectError(date_ce_date_error);
@@ -5117,8 +5076,6 @@ static bool date_period_init_finish(php_period_obj *dpobj, zend_long options, ze
51175076

51185077
dpobj->initialized = 1;
51195078

5120-
initialize_date_period_properties(dpobj);
5121-
51225079
return true;
51235080
}
51245081

@@ -5822,8 +5779,6 @@ static bool php_date_period_initialize_from_hash(php_period_obj *period_obj, Has
58225779

58235780
period_obj->initialized = 1;
58245781

5825-
initialize_date_period_properties(period_obj);
5826-
58275782
return 1;
58285783
} /* }}} */
58295784

@@ -5946,6 +5901,38 @@ PHP_METHOD(DatePeriod, __wakeup)
59465901
/* {{{ date_period_read_property */
59475902
static zval *date_period_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv)
59485903
{
5904+
if (date_period_is_internal_property(name)) {
5905+
if (type == BP_VAR_IS || type == BP_VAR_R) {
5906+
php_period_obj *period_obj = php_period_obj_from_obj(object);
5907+
5908+
if (zend_string_equals_literal(name, "start")) {
5909+
create_date_period_datetime(period_obj->start, period_obj->start_ce, rv);
5910+
return rv;
5911+
} else if (zend_string_equals_literal(name, "current")) {
5912+
create_date_period_datetime(period_obj->current, period_obj->start_ce, rv);
5913+
return rv;
5914+
} else if (zend_string_equals_literal(name, "end")) {
5915+
create_date_period_datetime(period_obj->end, period_obj->start_ce, rv);
5916+
return rv;
5917+
} else if (zend_string_equals_literal(name, "interval")) {
5918+
create_date_period_interval(period_obj->interval, rv);
5919+
return rv;
5920+
} else if (zend_string_equals_literal(name, "recurrences")) {
5921+
ZVAL_LONG(rv, period_obj->recurrences);
5922+
return rv;
5923+
} else if (zend_string_equals_literal(name, "include_start_date")) {
5924+
ZVAL_BOOL(rv, period_obj->include_start_date);
5925+
return rv;
5926+
} else if (zend_string_equals_literal(name, "include_end_date")) {
5927+
ZVAL_BOOL(rv, period_obj->include_end_date);
5928+
return rv;
5929+
}
5930+
} else {
5931+
zend_readonly_property_modification_error_ex("DatePeriod", ZSTR_VAL(name));
5932+
return &EG(uninitialized_zval);
5933+
}
5934+
}
5935+
59495936
if (type != BP_VAR_IS && type != BP_VAR_R) {
59505937
if (date_period_is_internal_property(name)) {
59515938
zend_readonly_property_modification_error_ex("DatePeriod", ZSTR_VAL(name));
@@ -5976,3 +5963,27 @@ static zval *date_period_get_property_ptr_ptr(zend_object *object, zend_string *
59765963

59775964
return zend_std_get_property_ptr_ptr(object, name, type, cache_slot);
59785965
}
5966+
5967+
static HashTable *date_period_get_properties_for(zend_object *object, zend_prop_purpose purpose)
5968+
{
5969+
switch (purpose) {
5970+
case ZEND_PROP_PURPOSE_DEBUG:
5971+
case ZEND_PROP_PURPOSE_SERIALIZE:
5972+
case ZEND_PROP_PURPOSE_VAR_EXPORT:
5973+
case ZEND_PROP_PURPOSE_JSON:
5974+
case ZEND_PROP_PURPOSE_ARRAY_CAST:
5975+
break;
5976+
default:
5977+
return zend_std_get_properties_for(object, purpose);
5978+
}
5979+
5980+
php_period_obj *period_obj = php_period_obj_from_obj(object);
5981+
HashTable *props = zend_array_dup(zend_std_get_properties(object));
5982+
if (!period_obj->initialized) {
5983+
return props;
5984+
}
5985+
5986+
date_period_object_to_hash(period_obj, props);
5987+
5988+
return props;
5989+
}

ext/date/php_date.stub.php

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -673,19 +673,40 @@ class DatePeriod implements IteratorAggregate
673673
/** @cvalue PHP_DATE_PERIOD_INCLUDE_END_DATE */
674674
public const int INCLUDE_END_DATE = UNKNOWN;
675675

676-
/** @readonly */
676+
/**
677+
* @readonly
678+
* @virtual
679+
*/
677680
public ?DateTimeInterface $start;
678-
/** @readonly */
681+
/**
682+
* @readonly
683+
* @virtual
684+
*/
679685
public ?DateTimeInterface $current;
680-
/** @readonly */
686+
/**
687+
* @readonly
688+
* @virtual
689+
*/
681690
public ?DateTimeInterface $end;
682-
/** @readonly */
691+
/**
692+
* @readonly
693+
* @virtual
694+
*/
683695
public ?DateInterval $interval;
684-
/** @readonly */
696+
/**
697+
* @readonly
698+
* @virtual
699+
*/
685700
public int $recurrences;
686-
/** @readonly */
701+
/**
702+
* @readonly
703+
* @virtual
704+
*/
687705
public bool $include_start_date;
688-
/** @readonly */
706+
/**
707+
* @readonly
708+
* @virtual
709+
*/
689710
public bool $include_end_date;
690711

691712
public static function createFromISO8601String(string $specification, int $options = 0): static {}

ext/date/php_date_arginfo.h

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)