diff --git a/Zend/tests/lazy_objects/gh19224.phpt b/Zend/tests/lazy_objects/gh19224.phpt new file mode 100644 index 0000000000000..20e14b00cb4cf --- /dev/null +++ b/Zend/tests/lazy_objects/gh19224.phpt @@ -0,0 +1,70 @@ +--TEST-- +GH-19224: Lazy ghosts may be partially initialized +--FILE-- +x = 1; + } + if ($prop === null || $prop === 'y') { + $obj->y = 2; + } +}; + +$obj = $rc->newLazyGhost($initializer, ReflectionClass::PARTIAL_INITIALIZATION); +var_dump($obj); +var_dump($obj->x); +var_dump($obj); +var_dump($obj->y); +var_dump($obj); + +$obj = $rc->newLazyGhost($initializer, ReflectionClass::PARTIAL_INITIALIZATION); +foreach ($obj as $prop) {} +var_dump($obj); + +// Object is realized when no specific prop is requested. +$obj = $rc->newLazyGhost(function () {}, ReflectionClass::PARTIAL_INITIALIZATION); +foreach ($obj as $prop) {} +var_dump($obj); + +?> +--EXPECTF-- +lazy ghost object(C)#%d (0) { + ["x"]=> + uninitialized(int) + ["y"]=> + uninitialized(int) +} +int(1) +lazy ghost object(C)#%d (1) { + ["x"]=> + int(1) + ["y"]=> + uninitialized(int) +} +int(2) +object(C)#%d (2) { + ["x"]=> + int(1) + ["y"]=> + int(2) +} +object(C)#%d (2) { + ["x"]=> + int(1) + ["y"]=> + int(2) +} +object(C)#%d (0) { + ["x"]=> + uninitialized(int) + ["y"]=> + uninitialized(int) +} diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index cf00804eda33b..7602a26da9ccb 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -558,6 +558,11 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj) /* Initialize a lazy object. */ ZEND_API zend_object *zend_lazy_object_init(zend_object *obj) +{ + return zend_lazy_object_init_ex(obj, NULL); +} + +ZEND_API zend_object *zend_lazy_object_init_ex(zend_object *obj, zend_string *prop) { ZEND_ASSERT(zend_object_is_lazy(obj)); @@ -590,6 +595,9 @@ ZEND_API zend_object *zend_lazy_object_init(zend_object *obj) zend_fcall_info_cache *initializer = zend_lazy_object_get_initializer_fcc(obj); + zend_lazy_object_info *info = zend_lazy_object_get_info(obj); + bool partial_initialization = info->flags & ZEND_LAZY_OBJECT_PARTIAL_INITIALIZATION; + /* Prevent reentrant initialization */ OBJ_EXTRA_FLAGS(obj) &= ~IS_OBJ_LAZY_UNINITIALIZED; @@ -618,14 +626,21 @@ ZEND_API zend_object *zend_lazy_object_init(zend_object *obj) /* Call initializer */ zval retval; - int argc = 1; - zval zobj; + int argc = partial_initialization ? 2 : 1; HashTable *named_params = NULL; zend_object *instance = NULL; - ZVAL_OBJ(&zobj, obj); + zval args[2]; + ZVAL_OBJ(&args[0], obj); + if (partial_initialization) { + if (prop) { + ZVAL_STR(&args[1], prop); + } else { + ZVAL_NULL(&args[1]); + } + } - zend_call_known_fcc(initializer, &retval, argc, &zobj, named_params); + zend_call_known_fcc(initializer, &retval, argc, args, named_params); if (EG(exception)) { zend_lazy_object_revert_init(obj, properties_table_snapshot, properties_snapshot); @@ -639,6 +654,25 @@ ZEND_API zend_object *zend_lazy_object_init(zend_object *obj) goto exit; } + /* Restore IS_PROP_LAZY flags for flags that remain uninitialized. */ + int lazy_properties_count = 0; + if (partial_initialization && prop) { + if (ce->default_properties_count) { + for (int i = 0; i < ce->default_properties_count; i++) { + zval *prop = &obj->properties_table[i]; + if (Z_TYPE_P(prop) == IS_UNDEF + && (Z_PROP_FLAG_P(&properties_table_snapshot[i]) & IS_PROP_LAZY)) { + lazy_properties_count++; + Z_PROP_FLAG_P(prop) = IS_PROP_UNINIT | IS_PROP_LAZY; + } + } + } + if (lazy_properties_count != 0) { + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED; + info->lazy_properties_count = lazy_properties_count; + } + } + if (properties_table_snapshot) { for (int i = 0; i < obj->ce->default_properties_count; i++) { zval *p = &properties_table_snapshot[i]; @@ -654,9 +688,11 @@ ZEND_API zend_object *zend_lazy_object_init(zend_object *obj) zend_release_properties(properties_snapshot); } - /* Must be very last in this function, for the - * zend_lazy_object_has_stale_info() check */ - zend_lazy_object_del_info(obj); + if (!(OBJ_EXTRA_FLAGS(obj) & IS_OBJ_LAZY_UNINITIALIZED)) { + /* Must be very last in this function, for the + * zend_lazy_object_has_stale_info() check */ + zend_lazy_object_del_info(obj); + } instance = obj; diff --git a/Zend/zend_lazy_objects.h b/Zend/zend_lazy_objects.h index fc0a908e7ad2f..2e0493e610f6d 100644 --- a/Zend/zend_lazy_objects.h +++ b/Zend/zend_lazy_objects.h @@ -36,9 +36,13 @@ /* Do not call destructor when making existing object lazy */ #define ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR (1<<4) +/* Initialization may not initialize all properties, keeping the object lazy. */ +#define ZEND_LAZY_OBJECT_PARTIAL_INITIALIZATION (1<<5) + #define ZEND_LAZY_OBJECT_USER_MASK ( \ ZEND_LAZY_OBJECT_SKIP_INITIALIZATION_ON_SERIALIZE | \ - ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR \ + ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR | \ + ZEND_LAZY_OBJECT_PARTIAL_INITIALIZATION \ ) #define ZEND_LAZY_OBJECT_STRATEGY_MASK ( \ @@ -62,6 +66,7 @@ ZEND_API zend_object *zend_object_make_lazy(zend_object *obj, zend_class_entry *class_type, zval *initializer_zv, zend_fcall_info_cache *initializer_fcc, zend_lazy_object_flags_t flags); ZEND_API zend_object *zend_lazy_object_init(zend_object *obj); +ZEND_API zend_object *zend_lazy_object_init_ex(zend_object *obj, zend_string *prop_name); ZEND_API zend_object *zend_lazy_object_mark_as_initialized(zend_object *obj); void zend_lazy_objects_init(zend_lazy_objects_store *store); diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index e6cee12d8eb64..767a075f8ba38 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -953,7 +953,7 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int uninit_error: if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { if (!prop_info || (Z_PROP_FLAG_P(retval) & IS_PROP_LAZY)) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { retval = &EG(uninitialized_zval); goto exit; @@ -1004,7 +1004,7 @@ static zval *forward_write_to_lazy_object(zend_object *zobj, zval backup; ZVAL_COPY(&backup, value); - zend_object *instance = zend_lazy_object_init(zobj); + zend_object *instance = zend_lazy_object_init_ex(zobj, name); if (UNEXPECTED(!instance)) { zval_ptr_dtor(&backup); return &EG(error_zval); @@ -1395,7 +1395,7 @@ ZEND_API zval *zend_std_get_property_ptr_ptr(zend_object *zobj, zend_string *nam UNEXPECTED((*zend_get_property_guard(zobj, name)) & IN_GET) || UNEXPECTED(prop_info && (Z_PROP_FLAG_P(retval) & IS_PROP_UNINIT))) { if (UNEXPECTED(zend_lazy_object_must_init(zobj) && (Z_PROP_FLAG_P(retval) & IS_PROP_LAZY))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { return &EG(error_zval); } @@ -1453,7 +1453,7 @@ ZEND_API zval *zend_std_get_property_ptr_ptr(zend_object *zobj, zend_string *nam } } if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { return &EG(error_zval); } @@ -1527,7 +1527,7 @@ ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void } if (UNEXPECTED(Z_PROP_FLAG_P(slot) & IS_PROP_UNINIT)) { if (UNEXPECTED(zend_lazy_object_must_init(zobj) && (Z_PROP_FLAG_P(slot) & IS_PROP_LAZY))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { return; } @@ -1580,7 +1580,7 @@ ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void } if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { return; } @@ -2396,7 +2396,7 @@ ZEND_API int zend_std_has_property(zend_object *zobj, zend_string *name, int has lazy_init: if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { if (!value || (Z_PROP_FLAG_P(value) & IS_PROP_LAZY)) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { result = 0; goto exit; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index fb5c7f6f3face..a18a90b5746d7 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2513,7 +2513,7 @@ ZEND_VM_C_LABEL(fast_assign_obj): } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(GET_OP2_ZVAL_PTR(BP_VAR_R)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); ZEND_VM_C_GOTO(free_and_exit_assign_obj); @@ -6162,7 +6162,7 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO } bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; - if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) { + if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) { if (c->ce->type == ZEND_USER_CLASS) { /* Recursion protection only applied to user constants, GH-18463 */ CONST_PROTECT_RECURSION(c); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 0107369ffa714..c30a32a9b0d7c 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -24171,7 +24171,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(RT_CONSTANT(opline, opline->op2)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -24325,7 +24325,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(RT_CONSTANT(opline, opline->op2)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -24479,7 +24479,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(RT_CONSTANT(opline, opline->op2)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -24633,7 +24633,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(RT_CONSTANT(opline, opline->op2)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -27177,7 +27177,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -27331,7 +27331,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -27485,7 +27485,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -27639,7 +27639,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -31531,7 +31531,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -31685,7 +31685,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -31839,7 +31839,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -31993,7 +31993,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -34280,7 +34280,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(RT_CONSTANT(opline, opline->op2)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -34434,7 +34434,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(RT_CONSTANT(opline, opline->op2)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -34588,7 +34588,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(RT_CONSTANT(opline, opline->op2)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -34742,7 +34742,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(RT_CONSTANT(opline, opline->op2)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -36463,7 +36463,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -36617,7 +36617,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -36771,7 +36771,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -36925,7 +36925,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -39110,7 +39110,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -39264,7 +39264,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -39418,7 +39418,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -39572,7 +39572,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -43469,7 +43469,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(RT_CONSTANT(opline, opline->op2)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -43623,7 +43623,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(RT_CONSTANT(opline, opline->op2)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -43777,7 +43777,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(RT_CONSTANT(opline, opline->op2)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -43931,7 +43931,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(RT_CONSTANT(opline, opline->op2)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -47422,7 +47422,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -47576,7 +47576,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -47730,7 +47730,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -47884,7 +47884,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -52922,7 +52922,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -53076,7 +53076,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -53230,7 +53230,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; @@ -53384,7 +53384,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(prop_offset))) { name = Z_STR_P(_get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC)); if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); + zobj = zend_lazy_object_init_ex(zobj, name); if (!zobj) { value = &EG(uninitialized_zval); goto free_and_exit_assign_obj; diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 3a37304dc2dc5..bff86a85316e8 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -5148,6 +5148,11 @@ void reflection_class_new_lazy(INTERNAL_FUNCTION_PARAMETERS, RETURN_THROWS(); } + if (strategy != ZEND_LAZY_OBJECT_STRATEGY_GHOST && (options & ZEND_LAZY_OBJECT_PARTIAL_INITIALIZATION)) { + zend_argument_error(reflection_exception_ptr, 2, + "does not accept ReflectionClass::PARTIAL_INITIALIZATION"); + } + if (is_reset) { if (zend_object_is_lazy(obj) && !zend_lazy_object_initialized(obj)) { zend_throw_exception_ex(reflection_exception_ptr, 0, "Object is already lazy"); diff --git a/ext/reflection/php_reflection.stub.php b/ext/reflection/php_reflection.stub.php index 67fb849db5845..d8312749cb265 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -250,6 +250,9 @@ class ReflectionClass implements Reflector /** @cvalue ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR */ public const int SKIP_DESTRUCTOR = UNKNOWN; + /** @cvalue ZEND_LAZY_OBJECT_PARTIAL_INITIALIZATION */ + public const int PARTIAL_INITIALIZATION = UNKNOWN; + public string $name; private function __clone(): void {} diff --git a/ext/reflection/php_reflection_arginfo.h b/ext/reflection/php_reflection_arginfo.h index 5b392ee3c2614..c95254416b485 100644 --- a/ext/reflection/php_reflection_arginfo.h +++ b/ext/reflection/php_reflection_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: ef9e7f30a29819489e17a9c100f55696d5d164e0 */ + * Stub hash: 95e712e047d33ca2fce1dadc9f9b11a1ab4a06f0 */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 1, IS_ARRAY, 0) ZEND_ARG_TYPE_INFO(0, modifiers, IS_LONG, 0) @@ -1540,6 +1540,12 @@ static zend_class_entry *register_class_ReflectionClass(zend_class_entry *class_ zend_declare_typed_class_constant(class_entry, const_SKIP_DESTRUCTOR_name, &const_SKIP_DESTRUCTOR_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_SKIP_DESTRUCTOR_name); + zval const_PARTIAL_INITIALIZATION_value; + ZVAL_LONG(&const_PARTIAL_INITIALIZATION_value, ZEND_LAZY_OBJECT_PARTIAL_INITIALIZATION); + zend_string *const_PARTIAL_INITIALIZATION_name = zend_string_init_interned("PARTIAL_INITIALIZATION", sizeof("PARTIAL_INITIALIZATION") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_PARTIAL_INITIALIZATION_name, &const_PARTIAL_INITIALIZATION_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_PARTIAL_INITIALIZATION_name); + zval property_name_default_value; ZVAL_UNDEF(&property_name_default_value); zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); diff --git a/ext/reflection/tests/ReflectionClass_toString_001.phpt b/ext/reflection/tests/ReflectionClass_toString_001.phpt index fd5d83e917419..1f9737979452b 100644 --- a/ext/reflection/tests/ReflectionClass_toString_001.phpt +++ b/ext/reflection/tests/ReflectionClass_toString_001.phpt @@ -11,13 +11,14 @@ echo $rc; --EXPECT-- Class [ class ReflectionClass implements Stringable, Reflector ] { - - Constants [6] { + - Constants [7] { Constant [ public int IS_IMPLICIT_ABSTRACT ] { 16 } Constant [ public int IS_EXPLICIT_ABSTRACT ] { 64 } Constant [ public int IS_FINAL ] { 32 } Constant [ public int IS_READONLY ] { 65536 } Constant [ public int SKIP_INITIALIZATION_ON_SERIALIZE ] { 8 } Constant [ public int SKIP_DESTRUCTOR ] { 16 } + Constant [ public int PARTIAL_INITIALIZATION ] { 32 } } - Static properties [0] {