mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Reduce memory overhead of DatePeriod via virtual properties (#15598)
Related to https://github.com/php/php-src/issues/11644 and https://github.com/php/php-src/issues/13988
This commit is contained in:
parent
8b0933b610
commit
181ea64cda
8 changed files with 476 additions and 96 deletions
|
@ -360,10 +360,12 @@ static int date_interval_compare_objects(zval *o1, zval *o2);
|
|||
static zval *date_interval_read_property(zend_object *object, zend_string *member, int type, void **cache_slot, zval *rv);
|
||||
static zval *date_interval_write_property(zend_object *object, zend_string *member, zval *value, void **cache_slot);
|
||||
static zval *date_interval_get_property_ptr_ptr(zend_object *object, zend_string *member, int type, void **cache_slot);
|
||||
static int date_period_has_property(zend_object *object, zend_string *name, int type, void **cache_slot);
|
||||
static zval *date_period_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv);
|
||||
static zval *date_period_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot);
|
||||
static zval *date_period_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot);
|
||||
|
||||
static void date_period_unset_property(zend_object *object, zend_string *name, void **cache_slot);
|
||||
static HashTable *date_period_get_properties_for(zend_object *object, zend_prop_purpose purpose);
|
||||
static int date_object_compare_timezone(zval *tz1, zval *tz2);
|
||||
|
||||
/* {{{ Module struct */
|
||||
|
@ -1505,45 +1507,6 @@ static void create_date_period_interval(timelib_rel_time *interval, zval *zv)
|
|||
}
|
||||
}
|
||||
|
||||
static void write_date_period_property(zend_object *obj, const char *name, const size_t name_len, zval *zv)
|
||||
{
|
||||
zend_string *property_name = zend_string_init(name, name_len, 0);
|
||||
|
||||
zend_std_write_property(obj, property_name, zv, NULL);
|
||||
|
||||
zval_ptr_dtor(zv);
|
||||
zend_string_release(property_name);
|
||||
}
|
||||
|
||||
static void initialize_date_period_properties(php_period_obj *period_obj)
|
||||
{
|
||||
zval zv;
|
||||
|
||||
/* rebuild properties */
|
||||
zend_std_get_properties_ex(&period_obj->std);
|
||||
|
||||
create_date_period_datetime(period_obj->start, period_obj->start_ce, &zv);
|
||||
write_date_period_property(&period_obj->std, "start", sizeof("start") - 1, &zv);
|
||||
|
||||
create_date_period_datetime(period_obj->current, period_obj->start_ce, &zv);
|
||||
write_date_period_property(&period_obj->std, "current", sizeof("current") - 1, &zv);
|
||||
|
||||
create_date_period_datetime(period_obj->end, period_obj->start_ce, &zv);
|
||||
write_date_period_property(&period_obj->std, "end", sizeof("end") - 1, &zv);
|
||||
|
||||
create_date_period_interval(period_obj->interval, &zv);
|
||||
write_date_period_property(&period_obj->std, "interval", sizeof("interval") - 1, &zv);
|
||||
|
||||
ZVAL_LONG(&zv, (zend_long) period_obj->recurrences);
|
||||
write_date_period_property(&period_obj->std, "recurrences", sizeof("recurrences") - 1, &zv);
|
||||
|
||||
ZVAL_BOOL(&zv, period_obj->include_start_date);
|
||||
write_date_period_property(&period_obj->std, "include_start_date", sizeof("include_start_date") - 1, &zv);
|
||||
|
||||
ZVAL_BOOL(&zv, period_obj->include_end_date);
|
||||
write_date_period_property(&period_obj->std, "include_end_date", sizeof("include_end_date") - 1, &zv);
|
||||
}
|
||||
|
||||
/* define an overloaded iterator structure */
|
||||
typedef struct {
|
||||
zend_object_iterator intern;
|
||||
|
@ -1663,10 +1626,7 @@ static void date_period_it_move_forward(zend_object_iterator *iter)
|
|||
zend_std_get_properties_ex(&object->std);
|
||||
|
||||
create_date_period_datetime(object->current, object->start_ce, ¤t_zv);
|
||||
zend_string *property_name = ZSTR_INIT_LITERAL("current", 0);
|
||||
zend_std_write_property(&object->std, property_name, ¤t_zv, NULL);
|
||||
zval_ptr_dtor(¤t_zv);
|
||||
zend_string_release(property_name);
|
||||
|
||||
iterator->current_index++;
|
||||
date_period_it_invalidate_current(iter);
|
||||
|
@ -1837,8 +1797,11 @@ static void date_register_classes(void) /* {{{ */
|
|||
date_object_handlers_period.clone_obj = date_object_clone_period;
|
||||
date_object_handlers_period.get_gc = date_object_get_gc_period;
|
||||
date_object_handlers_period.get_property_ptr_ptr = date_period_get_property_ptr_ptr;
|
||||
date_object_handlers_period.has_property = date_period_has_property;
|
||||
date_object_handlers_period.read_property = date_period_read_property;
|
||||
date_object_handlers_period.write_property = date_period_write_property;
|
||||
date_object_handlers_period.get_properties_for = date_period_get_properties_for;
|
||||
date_object_handlers_period.unset_property = date_period_unset_property;
|
||||
|
||||
date_ce_date_error = register_class_DateError(zend_ce_error);
|
||||
date_ce_date_object_error = register_class_DateObjectError(date_ce_date_error);
|
||||
|
@ -5138,8 +5101,6 @@ static bool date_period_init_finish(php_period_obj *dpobj, zend_long options, ze
|
|||
|
||||
dpobj->initialized = 1;
|
||||
|
||||
initialize_date_period_properties(dpobj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -5843,8 +5804,6 @@ static bool php_date_period_initialize_from_hash(php_period_obj *period_obj, Has
|
|||
|
||||
period_obj->initialized = 1;
|
||||
|
||||
initialize_date_period_properties(period_obj);
|
||||
|
||||
return 1;
|
||||
} /* }}} */
|
||||
|
||||
|
@ -5964,14 +5923,84 @@ PHP_METHOD(DatePeriod, __wakeup)
|
|||
zend_throw_error(NULL, "Invalid serialization data for DatePeriod object");
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
restore_custom_dateperiod_properties(object, myht);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int date_period_has_property(zend_object *object, zend_string *name, int type, void **cache_slot)
|
||||
{
|
||||
zval rv;
|
||||
zval *prop;
|
||||
|
||||
if (!date_period_is_internal_property(name)) {
|
||||
return zend_std_has_property(object, name, type, cache_slot);
|
||||
}
|
||||
|
||||
php_period_obj *period_obj = php_period_obj_from_obj(object);
|
||||
if (!period_obj->initialized) {
|
||||
switch (type) {
|
||||
case ZEND_PROPERTY_ISSET: /* Intentional fallthrough */
|
||||
case ZEND_PROPERTY_NOT_EMPTY:
|
||||
return 0;
|
||||
case ZEND_PROPERTY_EXISTS:
|
||||
return 1;
|
||||
EMPTY_SWITCH_DEFAULT_CASE()
|
||||
}
|
||||
}
|
||||
|
||||
if (type == ZEND_PROPERTY_EXISTS) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
prop = date_period_read_property(object, name, BP_VAR_IS, cache_slot, &rv);
|
||||
ZEND_ASSERT(prop != &EG(uninitialized_zval));
|
||||
|
||||
bool result;
|
||||
|
||||
if (type == ZEND_PROPERTY_NOT_EMPTY) {
|
||||
result = zend_is_true(prop);
|
||||
} else if (type == ZEND_PROPERTY_ISSET) {
|
||||
result = Z_TYPE_P(prop) != IS_NULL;
|
||||
} else {
|
||||
ZEND_UNREACHABLE();
|
||||
}
|
||||
|
||||
zval_ptr_dtor(prop);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* {{{ date_period_read_property */
|
||||
static zval *date_period_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv)
|
||||
{
|
||||
if (type != BP_VAR_IS && type != BP_VAR_R) {
|
||||
if (date_period_is_internal_property(name)) {
|
||||
if (date_period_is_internal_property(name)) {
|
||||
if (type == BP_VAR_IS || type == BP_VAR_R) {
|
||||
php_period_obj *period_obj = php_period_obj_from_obj(object);
|
||||
|
||||
if (zend_string_equals_literal(name, "start")) {
|
||||
create_date_period_datetime(period_obj->start, period_obj->start_ce, rv);
|
||||
return rv;
|
||||
} else if (zend_string_equals_literal(name, "current")) {
|
||||
create_date_period_datetime(period_obj->current, period_obj->start_ce, rv);
|
||||
return rv;
|
||||
} else if (zend_string_equals_literal(name, "end")) {
|
||||
create_date_period_datetime(period_obj->end, period_obj->start_ce, rv);
|
||||
return rv;
|
||||
} else if (zend_string_equals_literal(name, "interval")) {
|
||||
create_date_period_interval(period_obj->interval, rv);
|
||||
return rv;
|
||||
} else if (zend_string_equals_literal(name, "recurrences")) {
|
||||
ZVAL_LONG(rv, period_obj->recurrences);
|
||||
return rv;
|
||||
} else if (zend_string_equals_literal(name, "include_start_date")) {
|
||||
ZVAL_BOOL(rv, period_obj->include_start_date);
|
||||
return rv;
|
||||
} else if (zend_string_equals_literal(name, "include_end_date")) {
|
||||
ZVAL_BOOL(rv, period_obj->include_end_date);
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
zend_readonly_property_modification_error_ex("DatePeriod", ZSTR_VAL(name));
|
||||
return &EG(uninitialized_zval);
|
||||
}
|
||||
|
@ -6000,3 +6029,26 @@ static zval *date_period_get_property_ptr_ptr(zend_object *object, zend_string *
|
|||
|
||||
return zend_std_get_property_ptr_ptr(object, name, type, cache_slot);
|
||||
}
|
||||
|
||||
static HashTable *date_period_get_properties_for(zend_object *object, zend_prop_purpose purpose)
|
||||
{
|
||||
php_period_obj *period_obj = php_period_obj_from_obj(object);
|
||||
HashTable *props = zend_array_dup(zend_std_get_properties(object));
|
||||
if (!period_obj->initialized) {
|
||||
return props;
|
||||
}
|
||||
|
||||
date_period_object_to_hash(period_obj, props);
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
static void date_period_unset_property(zend_object *object, zend_string *name, void **cache_slot)
|
||||
{
|
||||
if (date_period_is_internal_property(name)) {
|
||||
zend_throw_error(NULL, "Cannot unset %s::$%s", ZSTR_VAL(object->ce->name), ZSTR_VAL(name));
|
||||
return;
|
||||
}
|
||||
|
||||
zend_std_unset_property(object, name, cache_slot);
|
||||
}
|
||||
|
|
|
@ -673,19 +673,40 @@ class DatePeriod implements IteratorAggregate
|
|||
/** @cvalue PHP_DATE_PERIOD_INCLUDE_END_DATE */
|
||||
public const int INCLUDE_END_DATE = UNKNOWN;
|
||||
|
||||
/** @readonly */
|
||||
/**
|
||||
* @readonly
|
||||
* @virtual
|
||||
*/
|
||||
public ?DateTimeInterface $start;
|
||||
/** @readonly */
|
||||
/**
|
||||
* @readonly
|
||||
* @virtual
|
||||
*/
|
||||
public ?DateTimeInterface $current;
|
||||
/** @readonly */
|
||||
/**
|
||||
* @readonly
|
||||
* @virtual
|
||||
*/
|
||||
public ?DateTimeInterface $end;
|
||||
/** @readonly */
|
||||
/**
|
||||
* @readonly
|
||||
* @virtual
|
||||
*/
|
||||
public ?DateInterval $interval;
|
||||
/** @readonly */
|
||||
/**
|
||||
* @readonly
|
||||
* @virtual
|
||||
*/
|
||||
public int $recurrences;
|
||||
/** @readonly */
|
||||
/**
|
||||
* @readonly
|
||||
* @virtual
|
||||
*/
|
||||
public bool $include_start_date;
|
||||
/** @readonly */
|
||||
/**
|
||||
* @readonly
|
||||
* @virtual
|
||||
*/
|
||||
public bool $include_end_date;
|
||||
|
||||
public static function createFromISO8601String(string $specification, int $options = 0): static {}
|
||||
|
|
16
ext/date/php_date_arginfo.h
generated
16
ext/date/php_date_arginfo.h
generated
|
@ -1,5 +1,5 @@
|
|||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 41c7662745d19808dd4550b37cd1b9f2aa94d75b */
|
||||
* Stub hash: d7a318f6fd85e23c6352323e03c323035a511738 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_strtotime, 0, 1, MAY_BE_LONG|MAY_BE_FALSE)
|
||||
ZEND_ARG_TYPE_INFO(0, datetime, IS_STRING, 0)
|
||||
|
@ -1120,46 +1120,46 @@ static zend_class_entry *register_class_DatePeriod(zend_class_entry *class_entry
|
|||
ZVAL_UNDEF(&property_start_default_value);
|
||||
zend_string *property_start_name = zend_string_init("start", sizeof("start") - 1, 1);
|
||||
zend_string *property_start_class_DateTimeInterface = zend_string_init("DateTimeInterface", sizeof("DateTimeInterface")-1, 1);
|
||||
zend_declare_typed_property(class_entry, property_start_name, &property_start_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_start_class_DateTimeInterface, 0, MAY_BE_NULL));
|
||||
zend_declare_typed_property(class_entry, property_start_name, &property_start_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_start_class_DateTimeInterface, 0, MAY_BE_NULL));
|
||||
zend_string_release(property_start_name);
|
||||
|
||||
zval property_current_default_value;
|
||||
ZVAL_UNDEF(&property_current_default_value);
|
||||
zend_string *property_current_name = zend_string_init("current", sizeof("current") - 1, 1);
|
||||
zend_string *property_current_class_DateTimeInterface = zend_string_init("DateTimeInterface", sizeof("DateTimeInterface")-1, 1);
|
||||
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));
|
||||
zend_declare_typed_property(class_entry, property_current_name, &property_current_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_current_class_DateTimeInterface, 0, MAY_BE_NULL));
|
||||
zend_string_release(property_current_name);
|
||||
|
||||
zval property_end_default_value;
|
||||
ZVAL_UNDEF(&property_end_default_value);
|
||||
zend_string *property_end_name = zend_string_init("end", sizeof("end") - 1, 1);
|
||||
zend_string *property_end_class_DateTimeInterface = zend_string_init("DateTimeInterface", sizeof("DateTimeInterface")-1, 1);
|
||||
zend_declare_typed_property(class_entry, property_end_name, &property_end_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_end_class_DateTimeInterface, 0, MAY_BE_NULL));
|
||||
zend_declare_typed_property(class_entry, property_end_name, &property_end_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_end_class_DateTimeInterface, 0, MAY_BE_NULL));
|
||||
zend_string_release(property_end_name);
|
||||
|
||||
zval property_interval_default_value;
|
||||
ZVAL_UNDEF(&property_interval_default_value);
|
||||
zend_string *property_interval_name = zend_string_init("interval", sizeof("interval") - 1, 1);
|
||||
zend_string *property_interval_class_DateInterval = zend_string_init("DateInterval", sizeof("DateInterval")-1, 1);
|
||||
zend_declare_typed_property(class_entry, property_interval_name, &property_interval_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_interval_class_DateInterval, 0, MAY_BE_NULL));
|
||||
zend_declare_typed_property(class_entry, property_interval_name, &property_interval_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_interval_class_DateInterval, 0, MAY_BE_NULL));
|
||||
zend_string_release(property_interval_name);
|
||||
|
||||
zval property_recurrences_default_value;
|
||||
ZVAL_UNDEF(&property_recurrences_default_value);
|
||||
zend_string *property_recurrences_name = zend_string_init("recurrences", sizeof("recurrences") - 1, 1);
|
||||
zend_declare_typed_property(class_entry, property_recurrences_name, &property_recurrences_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
|
||||
zend_declare_typed_property(class_entry, property_recurrences_name, &property_recurrences_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
|
||||
zend_string_release(property_recurrences_name);
|
||||
|
||||
zval property_include_start_date_default_value;
|
||||
ZVAL_UNDEF(&property_include_start_date_default_value);
|
||||
zend_string *property_include_start_date_name = zend_string_init("include_start_date", sizeof("include_start_date") - 1, 1);
|
||||
zend_declare_typed_property(class_entry, property_include_start_date_name, &property_include_start_date_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
|
||||
zend_declare_typed_property(class_entry, property_include_start_date_name, &property_include_start_date_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
|
||||
zend_string_release(property_include_start_date_name);
|
||||
|
||||
zval property_include_end_date_default_value;
|
||||
ZVAL_UNDEF(&property_include_end_date_default_value);
|
||||
zend_string *property_include_end_date_name = zend_string_init("include_end_date", sizeof("include_end_date") - 1, 1);
|
||||
zend_declare_typed_property(class_entry, property_include_end_date_name, &property_include_end_date_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
|
||||
zend_declare_typed_property(class_entry, property_include_end_date_name, &property_include_end_date_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
|
||||
zend_string_release(property_include_end_date_name);
|
||||
|
||||
return class_entry;
|
||||
|
|
42
ext/date/tests/date_period_is_property.phpt
Normal file
42
ext/date/tests/date_period_is_property.phpt
Normal file
|
@ -0,0 +1,42 @@
|
|||
--TEST--
|
||||
Test isset on DatePeriod instantiated without its constructor
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class MyDatePeriod extends DatePeriod {
|
||||
public int $my;
|
||||
}
|
||||
|
||||
$rc = new ReflectionClass('MyDatePeriod');
|
||||
$di = $rc->newInstanceWithoutConstructor();
|
||||
|
||||
var_dump(isset($di->start));
|
||||
var_dump(empty($di->start));
|
||||
var_dump(property_exists($di, "start"));
|
||||
|
||||
var_dump(isset($di->recurrences));
|
||||
var_dump(empty($di->recurrences));
|
||||
var_dump(property_exists($di, "recurrences"));
|
||||
|
||||
var_dump(isset($di->end));
|
||||
var_dump(empty($di->end));
|
||||
var_dump(property_exists($di, "end"));
|
||||
|
||||
var_dump(isset($di->my));
|
||||
var_dump(empty($di->my));
|
||||
var_dump(property_exists($di, "my"));
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(false)
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(true)
|
||||
bool(true)
|
187
ext/date/tests/date_period_properties.phpt
Normal file
187
ext/date/tests/date_period_properties.phpt
Normal file
|
@ -0,0 +1,187 @@
|
|||
--TEST--
|
||||
Test different usages of DatePeriod properties
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class MyDatePeriod extends DatePeriod {
|
||||
public int $prop = 3;
|
||||
}
|
||||
|
||||
$period = MyDatePeriod::createFromISO8601String("R4/2012-07-01T00:00:00Z/P7D");
|
||||
|
||||
var_dump($period);
|
||||
var_dump(json_encode($period));
|
||||
var_dump(serialize($period));
|
||||
var_dump(get_object_vars($period));
|
||||
var_dump(var_export($period));
|
||||
var_dump((array) ($period));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
object(MyDatePeriod)#%d (%d) {
|
||||
["prop"]=>
|
||||
int(3)
|
||||
["start"]=>
|
||||
object(DateTimeImmutable)#%d (%d) {
|
||||
["date"]=>
|
||||
string(26) "2012-07-01 00:00:00.000000"
|
||||
["timezone_type"]=>
|
||||
int(1)
|
||||
["timezone"]=>
|
||||
string(6) "+00:00"
|
||||
}
|
||||
["current"]=>
|
||||
NULL
|
||||
["end"]=>
|
||||
NULL
|
||||
["interval"]=>
|
||||
object(DateInterval)#%d (%d) {
|
||||
["y"]=>
|
||||
int(0)
|
||||
["m"]=>
|
||||
int(0)
|
||||
["d"]=>
|
||||
int(7)
|
||||
["h"]=>
|
||||
int(0)
|
||||
["i"]=>
|
||||
int(0)
|
||||
["s"]=>
|
||||
int(0)
|
||||
["f"]=>
|
||||
float(0)
|
||||
["invert"]=>
|
||||
int(0)
|
||||
["days"]=>
|
||||
bool(false)
|
||||
["from_string"]=>
|
||||
bool(false)
|
||||
}
|
||||
["recurrences"]=>
|
||||
int(5)
|
||||
["include_start_date"]=>
|
||||
bool(true)
|
||||
["include_end_date"]=>
|
||||
bool(false)
|
||||
}
|
||||
string(%d) "{"prop":3,"start":{"date":"2012-07-01 00:00:00.000000","timezone_type":1,"timezone":"+00:00"},"current":null,"end":null,"interval":{"y":0,"m":0,"d":7,"h":0,"i":0,"s":0,"f":0,"invert":0,"days":false,"from_string":false},"recurrences":5,"include_start_date":true,"include_end_date":false}"
|
||||
string(%d) "O:12:"MyDatePeriod":8:{s:5:"start";O:17:"DateTimeImmutable":3:{s:4:"date";s:26:"2012-07-01 00:00:00.000000";s:13:"timezone_type";i:1;s:8:"timezone";s:6:"+00:00";}s:7:"current";N;s:3:"end";N;s:8:"interval";O:12:"DateInterval":10:{s:1:"y";i:0;s:1:"m";i:0;s:1:"d";i:7;s:1:"h";i:0;s:1:"i";i:0;s:1:"s";i:0;s:1:"f";d:0;s:6:"invert";i:0;s:4:"days";b:0;s:11:"from_string";b:0;}s:11:"recurrences";i:5;s:18:"include_start_date";b:1;s:16:"include_end_date";b:0;s:4:"prop";i:3;}"
|
||||
array(%d) {
|
||||
["prop"]=>
|
||||
int(3)
|
||||
["start"]=>
|
||||
object(DateTimeImmutable)#%d (%d) {
|
||||
["date"]=>
|
||||
string(26) "2012-07-01 00:00:00.000000"
|
||||
["timezone_type"]=>
|
||||
int(1)
|
||||
["timezone"]=>
|
||||
string(6) "+00:00"
|
||||
}
|
||||
["current"]=>
|
||||
NULL
|
||||
["end"]=>
|
||||
NULL
|
||||
["interval"]=>
|
||||
object(DateInterval)#%d (%d) {
|
||||
["y"]=>
|
||||
int(0)
|
||||
["m"]=>
|
||||
int(0)
|
||||
["d"]=>
|
||||
int(7)
|
||||
["h"]=>
|
||||
int(0)
|
||||
["i"]=>
|
||||
int(0)
|
||||
["s"]=>
|
||||
int(0)
|
||||
["f"]=>
|
||||
float(0)
|
||||
["invert"]=>
|
||||
int(0)
|
||||
["days"]=>
|
||||
bool(false)
|
||||
["from_string"]=>
|
||||
bool(false)
|
||||
}
|
||||
["recurrences"]=>
|
||||
int(5)
|
||||
["include_start_date"]=>
|
||||
bool(true)
|
||||
["include_end_date"]=>
|
||||
bool(false)
|
||||
}
|
||||
\MyDatePeriod::__set_state(array(
|
||||
'prop' => 3,
|
||||
'start' =>
|
||||
\DateTimeImmutable::__set_state(array(
|
||||
'date' => '2012-07-01 00:00:00.000000',
|
||||
'timezone_type' => 1,
|
||||
'timezone' => '+00:00',
|
||||
)),
|
||||
'current' => NULL,
|
||||
'end' => NULL,
|
||||
'interval' =>
|
||||
\DateInterval::__set_state(array(
|
||||
'y' => 0,
|
||||
'm' => 0,
|
||||
'd' => 7,
|
||||
'h' => 0,
|
||||
'i' => 0,
|
||||
's' => 0,
|
||||
'f' => 0.0,
|
||||
'invert' => 0,
|
||||
'days' => false,
|
||||
'from_string' => false,
|
||||
)),
|
||||
'recurrences' => 5,
|
||||
'include_start_date' => true,
|
||||
'include_end_date' => false,
|
||||
))NULL
|
||||
array(%d) {
|
||||
["prop"]=>
|
||||
int(3)
|
||||
["start"]=>
|
||||
object(DateTimeImmutable)#%d (%d) {
|
||||
["date"]=>
|
||||
string(26) "2012-07-01 00:00:00.000000"
|
||||
["timezone_type"]=>
|
||||
int(1)
|
||||
["timezone"]=>
|
||||
string(6) "+00:00"
|
||||
}
|
||||
["current"]=>
|
||||
NULL
|
||||
["end"]=>
|
||||
NULL
|
||||
["interval"]=>
|
||||
object(DateInterval)#%d (%d) {
|
||||
["y"]=>
|
||||
int(0)
|
||||
["m"]=>
|
||||
int(0)
|
||||
["d"]=>
|
||||
int(7)
|
||||
["h"]=>
|
||||
int(0)
|
||||
["i"]=>
|
||||
int(0)
|
||||
["s"]=>
|
||||
int(0)
|
||||
["f"]=>
|
||||
float(0)
|
||||
["invert"]=>
|
||||
int(0)
|
||||
["days"]=>
|
||||
bool(false)
|
||||
["from_string"]=>
|
||||
bool(false)
|
||||
}
|
||||
["recurrences"]=>
|
||||
int(5)
|
||||
["include_start_date"]=>
|
||||
bool(true)
|
||||
["include_end_date"]=>
|
||||
bool(false)
|
||||
}
|
|
@ -11,9 +11,9 @@ $period = new DatePeriod($start, $interval, $end);
|
|||
try {
|
||||
$period->__unserialize(
|
||||
[
|
||||
"current" => new DateTime,
|
||||
"start" => new DateTime,
|
||||
"end" => new DateTime,
|
||||
"current" => new DateTime("2024-08-27 00:00:00"),
|
||||
"start" => new DateTime("2024-08-28 00:00:00"),
|
||||
"end" => new DateTime("2024-08-29 00:00:00"),
|
||||
"interval" => new DateInterval('P2D'),
|
||||
"recurrences" => 2,
|
||||
"include_start_date" => "wrong type",
|
||||
|
@ -33,18 +33,25 @@ object(DatePeriod)#%d (%d) {
|
|||
["start"]=>
|
||||
object(DateTime)#%d (%d) {
|
||||
["date"]=>
|
||||
string(26) "2022-07-14 00:00:00.000000"
|
||||
string(26) "2024-08-28 00:00:00.000000"
|
||||
["timezone_type"]=>
|
||||
int(3)
|
||||
["timezone"]=>
|
||||
string(3) "UTC"
|
||||
}
|
||||
["current"]=>
|
||||
NULL
|
||||
object(DateTime)#%d (%d) {
|
||||
["date"]=>
|
||||
string(26) "2024-08-27 00:00:00.000000"
|
||||
["timezone_type"]=>
|
||||
int(3)
|
||||
["timezone"]=>
|
||||
string(3) "UTC"
|
||||
}
|
||||
["end"]=>
|
||||
object(DateTime)#%d (%d) {
|
||||
["date"]=>
|
||||
string(26) "2022-07-16 00:00:00.000000"
|
||||
string(26) "2024-08-29 00:00:00.000000"
|
||||
["timezone_type"]=>
|
||||
int(3)
|
||||
["timezone"]=>
|
||||
|
@ -57,7 +64,7 @@ object(DatePeriod)#%d (%d) {
|
|||
["m"]=>
|
||||
int(0)
|
||||
["d"]=>
|
||||
int(1)
|
||||
int(2)
|
||||
["h"]=>
|
||||
int(0)
|
||||
["i"]=>
|
||||
|
@ -74,7 +81,7 @@ object(DatePeriod)#%d (%d) {
|
|||
bool(false)
|
||||
}
|
||||
["recurrences"]=>
|
||||
int(1)
|
||||
int(2)
|
||||
["include_start_date"]=>
|
||||
bool(true)
|
||||
["include_end_date"]=>
|
||||
|
|
71
ext/date/tests/date_period_unset_property.phpt
Normal file
71
ext/date/tests/date_period_unset_property.phpt
Normal file
|
@ -0,0 +1,71 @@
|
|||
--TEST--
|
||||
Test unsetting DatePeriod properties
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class MyDatePeriod extends DatePeriod {
|
||||
public int $prop = 3;
|
||||
}
|
||||
|
||||
$period = new MyDatePeriod(new DateTimeImmutable("now"), DateInterval::createFromDateString("tomorrow"), 1);
|
||||
|
||||
unset($period->prop);
|
||||
|
||||
try {
|
||||
$period->prop;
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
unset($period->start);
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
unset($period->current);
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
unset($period->end);
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
unset($period->interval);
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
unset($period->recurrences);
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
unset($period->include_start_date);
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
unset($period->include_end_date);
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Typed property MyDatePeriod::$prop must not be accessed before initialization
|
||||
Cannot unset MyDatePeriod::$start
|
||||
Cannot unset MyDatePeriod::$current
|
||||
Cannot unset MyDatePeriod::$end
|
||||
Cannot unset MyDatePeriod::$interval
|
||||
Cannot unset MyDatePeriod::$recurrences
|
||||
Cannot unset MyDatePeriod::$include_start_date
|
||||
Cannot unset MyDatePeriod::$include_end_date
|
|
@ -26,9 +26,17 @@ $u = unserialize($s);
|
|||
var_dump($i, str_replace(chr(0), '!', $s), $u);
|
||||
?>
|
||||
--EXPECTF--
|
||||
object(I)#1 (11) {
|
||||
object(I)#%d (%d) {
|
||||
["var1":"I":private]=>
|
||||
int(1)
|
||||
["var2":"I":private]=>
|
||||
int(2)
|
||||
["var3":protected]=>
|
||||
int(3)
|
||||
["var4":protected]=>
|
||||
int(4)
|
||||
["start"]=>
|
||||
object(DateTimeImmutable)#5 (3) {
|
||||
object(DateTimeImmutable)#%d (%d) {
|
||||
["date"]=>
|
||||
string(26) "2023-03-03 16:24:00.000000"
|
||||
["timezone_type"]=>
|
||||
|
@ -39,7 +47,7 @@ object(I)#1 (11) {
|
|||
["current"]=>
|
||||
NULL
|
||||
["end"]=>
|
||||
object(DateTimeImmutable)#6 (3) {
|
||||
object(DateTimeImmutable)#%d (%d) {
|
||||
["date"]=>
|
||||
string(26) "2023-03-09 16:24:00.000000"
|
||||
["timezone_type"]=>
|
||||
|
@ -48,7 +56,7 @@ object(I)#1 (11) {
|
|||
string(3) "UTC"
|
||||
}
|
||||
["interval"]=>
|
||||
object(DateInterval)#7 (10) {
|
||||
object(DateInterval)#%d (%d) {
|
||||
["y"]=>
|
||||
int(0)
|
||||
["m"]=>
|
||||
|
@ -76,19 +84,19 @@ object(I)#1 (11) {
|
|||
bool(true)
|
||||
["include_end_date"]=>
|
||||
bool(false)
|
||||
["var1":"I":private]=>
|
||||
int(1)
|
||||
["var2":"I":private]=>
|
||||
int(2)
|
||||
["var3":protected]=>
|
||||
int(3)
|
||||
["var4":protected]=>
|
||||
int(4)
|
||||
}
|
||||
string(631) "O:1:"I":11:{s:5:"start";O:17:"DateTimeImmutable":3:{s:4:"date";s:26:"2023-03-03 16:24:00.000000";s:13:"timezone_type";i:3;s:8:"timezone";s:3:"UTC";}s:7:"current";N;s:3:"end";O:17:"DateTimeImmutable":3:{s:4:"date";s:26:"2023-03-09 16:24:00.000000";s:13:"timezone_type";i:3;s:8:"timezone";s:3:"UTC";}s:8:"interval";O:12:"DateInterval":10:{s:1:"y";i:0;s:1:"m";i:0;s:1:"d";i:0;s:1:"h";i:1;s:1:"i";i:0;s:1:"s";i:0;s:1:"f";d:0;s:6:"invert";i:0;s:4:"days";b:0;s:11:"from_string";b:0;}s:11:"recurrences";i:1;s:18:"include_start_date";b:1;s:16:"include_end_date";b:0;s:7:"!I!var1";i:1;s:7:"!I!var2";i:2;s:7:"!*!var3";i:3;s:7:"!*!var4";i:4;}"
|
||||
object(I)#2 (11) {
|
||||
object(I)#%d (%d) {
|
||||
["var1":"I":private]=>
|
||||
int(1)
|
||||
["var2":"I":private]=>
|
||||
int(2)
|
||||
["var3":protected]=>
|
||||
int(3)
|
||||
["var4":protected]=>
|
||||
int(4)
|
||||
["start"]=>
|
||||
object(DateTimeImmutable)#9 (3) {
|
||||
object(DateTimeImmutable)#%d (%d) {
|
||||
["date"]=>
|
||||
string(26) "2023-03-03 16:24:00.000000"
|
||||
["timezone_type"]=>
|
||||
|
@ -99,7 +107,7 @@ object(I)#2 (11) {
|
|||
["current"]=>
|
||||
NULL
|
||||
["end"]=>
|
||||
object(DateTimeImmutable)#10 (3) {
|
||||
object(DateTimeImmutable)#%d (%d) {
|
||||
["date"]=>
|
||||
string(26) "2023-03-09 16:24:00.000000"
|
||||
["timezone_type"]=>
|
||||
|
@ -108,7 +116,7 @@ object(I)#2 (11) {
|
|||
string(3) "UTC"
|
||||
}
|
||||
["interval"]=>
|
||||
object(DateInterval)#11 (10) {
|
||||
object(DateInterval)#%d (%d) {
|
||||
["y"]=>
|
||||
int(0)
|
||||
["m"]=>
|
||||
|
@ -136,12 +144,4 @@ object(I)#2 (11) {
|
|||
bool(true)
|
||||
["include_end_date"]=>
|
||||
bool(false)
|
||||
["var1":"I":private]=>
|
||||
int(1)
|
||||
["var2":"I":private]=>
|
||||
int(2)
|
||||
["var3":protected]=>
|
||||
int(3)
|
||||
["var4":protected]=>
|
||||
int(4)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue