From 8347adada1dd28d0b28fe131f4e5e18ab1b26ea6 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Fri, 19 May 2023 12:55:05 +0200 Subject: [PATCH 01/56] Lazy objects --- Zend/tests/lazy_objects/003.phpt | 65 ++ Zend/tests/lazy_objects/004.phpt | 65 ++ Zend/tests/lazy_objects/005.phpt | 164 +++++ Zend/tests/lazy_objects/006.phpt | 48 ++ Zend/tests/lazy_objects/007.phpt | 64 ++ Zend/tests/lazy_objects/008.phpt | 47 ++ Zend/tests/lazy_objects/009.phpt | 43 ++ Zend/tests/lazy_objects/010.phpt | 42 ++ Zend/tests/lazy_objects/011.phpt | 62 ++ Zend/tests/lazy_objects/012.phpt | 58 ++ Zend/tests/lazy_objects/013.phpt | 65 ++ Zend/tests/lazy_objects/014.phpt | 34 + Zend/tests/lazy_objects/015.phpt | 37 + Zend/tests/lazy_objects/016.phpt | 45 ++ Zend/tests/lazy_objects/017.phpt | 74 ++ Zend/tests/lazy_objects/018.phpt | 57 ++ Zend/tests/lazy_objects/019.phpt | 56 ++ Zend/tests/lazy_objects/020.phpt | 80 +++ Zend/tests/lazy_objects/021.phpt | 81 +++ Zend/tests/lazy_objects/024.phpt | 36 + Zend/tests/lazy_objects/025.phpt | 55 ++ Zend/tests/lazy_objects/026.phpt | 59 ++ Zend/tests/lazy_objects/027.phpt | 63 ++ Zend/tests/lazy_objects/clone_001.phpt | 71 ++ Zend/tests/lazy_objects/clone_002.phpt | 77 ++ Zend/tests/lazy_objects/clone_003.phpt | 56 ++ Zend/tests/lazy_objects/clone_004.phpt | 73 ++ Zend/tests/lazy_objects/clone_007.phpt | 35 + Zend/tests/lazy_objects/clone_008.phpt | 56 ++ Zend/tests/lazy_objects/clone_009.phpt | 40 ++ Zend/tests/lazy_objects/feedback_001.phpt | 49 ++ Zend/tests/lazy_objects/feedback_002.phpt | 36 + Zend/tests/lazy_objects/feedback_003.phpt | 33 + Zend/tests/lazy_objects/feedback_004.phpt | 29 + Zend/tests/lazy_objects/feedback_005.phpt | 50 ++ Zend/tests/lazy_objects/feedback_006.phpt | 29 + Zend/tests/lazy_objects/feedback_007.phpt | 31 + Zend/tests/lazy_objects/feedback_008.phpt | 53 ++ Zend/tests/lazy_objects/feedback_009.phpt | 29 + Zend/tests/lazy_objects/fetch_001.phpt | 72 ++ Zend/tests/lazy_objects/fetch_002.phpt | 65 ++ Zend/tests/lazy_objects/fetch_003.phpt | 65 ++ Zend/tests/lazy_objects/fetch_004.phpt | 69 ++ Zend/tests/lazy_objects/fetch_005.phpt | 60 ++ Zend/tests/lazy_objects/fetch_006.phpt | 66 ++ Zend/tests/lazy_objects/fetch_007.phpt | 70 ++ Zend/tests/lazy_objects/fetch_008.phpt | 63 ++ Zend/tests/lazy_objects/fetch_009.phpt | 63 ++ Zend/tests/lazy_objects/fetch_010.phpt | 65 ++ Zend/tests/lazy_objects/fetch_011.phpt | 62 ++ Zend/tests/lazy_objects/fetch_012.phpt | 62 ++ Zend/tests/lazy_objects/fetch_013.phpt | 93 +++ Zend/tests/lazy_objects/fetch_014.phpt | 91 +++ Zend/tests/lazy_objects/fetch_015.phpt | 87 +++ Zend/tests/lazy_objects/fetch_016.phpt | 75 ++ Zend/tests/lazy_objects/fetch_017.phpt | 76 ++ Zend/tests/lazy_objects/fetch_018.phpt | 62 ++ Zend/tests/lazy_objects/gc_001.phpt | 54 ++ Zend/tests/lazy_objects/gc_002.phpt | 59 ++ Zend/tests/lazy_objects/gc_003.phpt | 59 ++ Zend/tests/lazy_objects/gc_004.phpt | 67 ++ Zend/tests/lazy_objects/gc_005.phpt | 68 ++ Zend/tests/lazy_objects/get_initializer.phpt | 52 ++ Zend/tests/lazy_objects/ghost_001.phpt | 46 ++ Zend/tests/lazy_objects/ghost_002.phpt | 45 ++ .../lazy_objects/init_exception_001.phpt | 51 ++ .../lazy_objects/init_exception_002.phpt | 72 ++ .../lazy_objects/init_exception_003.phpt | 83 +++ .../lazy_objects/init_exception_005.phpt | 77 ++ .../lazy_objects/init_exception_006.phpt | 84 +++ .../lazy_objects/init_exception_009.phpt | 95 +++ .../lazy_objects/init_exception_010.phpt | 100 +++ .../lazy_objects/init_exception_011.phpt | 108 +++ .../lazy_objects/init_exception_012.phpt | 59 ++ Zend/tests/lazy_objects/initialize_001.phpt | 62 ++ Zend/tests/lazy_objects/initialize_002.phpt | 60 ++ Zend/tests/lazy_objects/initialize_005.phpt | 51 ++ .../lazy_objects/is_initialized_001.phpt | 26 + .../is_uninitialized_lazy_object.phpt | 31 + Zend/tests/lazy_objects/isset_001.phpt | 72 ++ Zend/tests/lazy_objects/isset_002.phpt | 75 ++ Zend/tests/lazy_objects/isset_003.phpt | 64 ++ .../make_lazy_already_exception.phpt | 55 ++ .../make_lazy_destructor_001.phpt | 59 ++ .../make_lazy_destructor_002.phpt | 57 ++ .../make_lazy_destructor_003.phpt | 55 ++ .../lazy_objects/mark_as_initialized_001.phpt | 66 ++ .../lazy_objects/new_instance_lazy_001.phpt | 20 + .../lazy_objects/new_instance_lazy_002.phpt | 21 + .../lazy_objects/new_instance_lazy_003.phpt | 22 + .../lazy_objects/new_instance_lazy_004.phpt | 18 + .../lazy_objects/new_instance_lazy_005.phpt | 21 + .../object_with_ast_const_001.phpt | 27 + .../object_with_ast_const_002.phpt | 26 + .../props_of_proxy_must_not_be_lazy_004.phpt | 90 +++ Zend/tests/lazy_objects/realize_001.phpt | 95 +++ Zend/tests/lazy_objects/realize_002.phpt | 100 +++ Zend/tests/lazy_objects/realize_003.phpt | 78 ++ ...lection_lazy_object_skip_property_001.phpt | 349 +++++++++ .../reflection_to_string_does_not_init.phpt | 45 ++ ...as_lazy_can_reset_initialized_proxies.phpt | 55 ++ ...eset_as_lazy_ignores_additional_props.phpt | 103 +++ .../lazy_objects/reset_readonly_001.phpt | 71 ++ Zend/tests/lazy_objects/rfc_example_001.phpt | 40 ++ Zend/tests/lazy_objects/rfc_example_002.phpt | 44 ++ Zend/tests/lazy_objects/rfc_example_003.phpt | 51 ++ Zend/tests/lazy_objects/rfc_example_004.phpt | 69 ++ Zend/tests/lazy_objects/rfc_example_005.phpt | 71 ++ Zend/tests/lazy_objects/rfc_example_006.phpt | 64 ++ Zend/tests/lazy_objects/rfc_example_007.phpt | 31 + Zend/tests/lazy_objects/rfc_example_008.phpt | 25 + Zend/tests/lazy_objects/rfc_example_009.phpt | 40 ++ Zend/tests/lazy_objects/rfc_example_010.phpt | 25 + Zend/tests/lazy_objects/rfc_example_011.phpt | 81 +++ Zend/tests/lazy_objects/rfc_example_012.phpt | 80 +++ Zend/tests/lazy_objects/serialize_001.phpt | 44 ++ Zend/tests/lazy_objects/serialize_002.phpt | 47 ++ Zend/tests/lazy_objects/serialize_003.phpt | 52 ++ Zend/tests/lazy_objects/serialize_004.phpt | 55 ++ Zend/tests/lazy_objects/serialize_005.phpt | 48 ++ Zend/tests/lazy_objects/serialize_006.phpt | 53 ++ Zend/tests/lazy_objects/serialize_007.phpt | 53 ++ Zend/tests/lazy_objects/serialize_008.phpt | 49 ++ Zend/tests/lazy_objects/serialize_009.phpt | 56 ++ Zend/tests/lazy_objects/serialize_010.phpt | 47 ++ .../tests/lazy_objects/set_raw_value_001.phpt | 47 ++ .../tests/lazy_objects/set_raw_value_002.phpt | 50 ++ .../tests/lazy_objects/set_raw_value_003.phpt | 52 ++ .../tests/lazy_objects/set_raw_value_004.phpt | 51 ++ .../tests/lazy_objects/set_raw_value_005.phpt | 68 ++ .../tests/lazy_objects/set_raw_value_006.phpt | 71 ++ .../tests/lazy_objects/set_raw_value_007.phpt | 54 ++ .../tests/lazy_objects/set_raw_value_008.phpt | 43 ++ .../tests/lazy_objects/set_raw_value_009.phpt | 54 ++ .../lazy_objects/skip_initialization_001.phpt | 59 ++ .../lazy_objects/skip_initialization_002.phpt | 53 ++ .../lazy_objects/skip_initialization_003.phpt | 52 ++ .../lazy_objects/skip_initialization_004.phpt | 54 ++ .../lazy_objects/skip_initialization_005.phpt | 54 ++ .../lazy_objects/skip_initialization_006.phpt | 61 ++ .../lazy_objects/skip_initialization_007.phpt | 75 ++ .../lazy_objects/skip_initialization_008.phpt | 76 ++ .../lazy_objects/skip_initialization_009.phpt | 67 ++ .../lazy_objects/skip_initialization_010.phpt | 43 ++ Zend/tests/lazy_objects/unclean_shutdown.phpt | 17 + Zend/tests/lazy_objects/unset_001.phpt | 66 ++ Zend/tests/lazy_objects/unset_003.phpt | 60 ++ Zend/tests/lazy_objects/unset_004.phpt | 70 ++ Zend/tests/lazy_objects/unset_005.phpt | 68 ++ Zend/tests/lazy_objects/unset_006.phpt | 65 ++ Zend/tests/lazy_objects/unset_007.phpt | 60 ++ Zend/tests/lazy_objects/unset_008.phpt | 60 ++ Zend/tests/lazy_objects/unset_009.phpt | 78 ++ Zend/tests/lazy_objects/unset_010.phpt | 68 ++ Zend/tests/lazy_objects/use_case_001.phpt | 44 ++ Zend/tests/lazy_objects/use_case_001b.phpt | 44 ++ Zend/tests/lazy_objects/use_case_002.phpt | 52 ++ Zend/tests/lazy_objects/write_001.phpt | 69 ++ Zend/tests/lazy_objects/write_002.phpt | 74 ++ Zend/tests/lazy_objects/write_003.phpt | 64 ++ Zend/tests/lazy_objects/write_004.phpt | 64 ++ Zend/tests/lazy_objects/write_005.phpt | 48 ++ Zend/tests/lazy_objects/write_006.phpt | 81 +++ Zend/zend_builtin_functions.c | 2 +- Zend/zend_execute_API.c | 2 + Zend/zend_globals.h | 2 + Zend/zend_lazy_objects.c | 668 ++++++++++++++++++ Zend/zend_lazy_objects.h | 107 +++ Zend/zend_object_handlers.c | 175 ++++- Zend/zend_object_handlers.h | 9 + Zend/zend_objects.c | 83 ++- Zend/zend_objects.h | 4 + Zend/zend_operators.c | 3 +- Zend/zend_types.h | 9 + Zend/zend_vm_def.h | 3 +- Zend/zend_vm_execute.h | 12 +- configure.ac | 1 + ext/ffi/ffi.c | 1 + ext/json/json_encoder.c | 9 + ext/reflection/php_reflection.c | 337 ++++++++- ext/reflection/php_reflection.h | 1 + ext/reflection/php_reflection.stub.php | 26 + ext/reflection/php_reflection_arginfo.h | 72 +- .../tests/ReflectionClass_toString_001.phpt | 76 +- ext/standard/var.c | 40 +- 185 files changed, 11416 insertions(+), 53 deletions(-) create mode 100644 Zend/tests/lazy_objects/003.phpt create mode 100644 Zend/tests/lazy_objects/004.phpt create mode 100644 Zend/tests/lazy_objects/005.phpt create mode 100644 Zend/tests/lazy_objects/006.phpt create mode 100644 Zend/tests/lazy_objects/007.phpt create mode 100644 Zend/tests/lazy_objects/008.phpt create mode 100644 Zend/tests/lazy_objects/009.phpt create mode 100644 Zend/tests/lazy_objects/010.phpt create mode 100644 Zend/tests/lazy_objects/011.phpt create mode 100644 Zend/tests/lazy_objects/012.phpt create mode 100644 Zend/tests/lazy_objects/013.phpt create mode 100644 Zend/tests/lazy_objects/014.phpt create mode 100644 Zend/tests/lazy_objects/015.phpt create mode 100644 Zend/tests/lazy_objects/016.phpt create mode 100644 Zend/tests/lazy_objects/017.phpt create mode 100644 Zend/tests/lazy_objects/018.phpt create mode 100644 Zend/tests/lazy_objects/019.phpt create mode 100644 Zend/tests/lazy_objects/020.phpt create mode 100644 Zend/tests/lazy_objects/021.phpt create mode 100644 Zend/tests/lazy_objects/024.phpt create mode 100644 Zend/tests/lazy_objects/025.phpt create mode 100644 Zend/tests/lazy_objects/026.phpt create mode 100644 Zend/tests/lazy_objects/027.phpt create mode 100644 Zend/tests/lazy_objects/clone_001.phpt create mode 100644 Zend/tests/lazy_objects/clone_002.phpt create mode 100644 Zend/tests/lazy_objects/clone_003.phpt create mode 100644 Zend/tests/lazy_objects/clone_004.phpt create mode 100644 Zend/tests/lazy_objects/clone_007.phpt create mode 100644 Zend/tests/lazy_objects/clone_008.phpt create mode 100644 Zend/tests/lazy_objects/clone_009.phpt create mode 100644 Zend/tests/lazy_objects/feedback_001.phpt create mode 100644 Zend/tests/lazy_objects/feedback_002.phpt create mode 100644 Zend/tests/lazy_objects/feedback_003.phpt create mode 100644 Zend/tests/lazy_objects/feedback_004.phpt create mode 100644 Zend/tests/lazy_objects/feedback_005.phpt create mode 100644 Zend/tests/lazy_objects/feedback_006.phpt create mode 100644 Zend/tests/lazy_objects/feedback_007.phpt create mode 100644 Zend/tests/lazy_objects/feedback_008.phpt create mode 100644 Zend/tests/lazy_objects/feedback_009.phpt create mode 100644 Zend/tests/lazy_objects/fetch_001.phpt create mode 100644 Zend/tests/lazy_objects/fetch_002.phpt create mode 100644 Zend/tests/lazy_objects/fetch_003.phpt create mode 100644 Zend/tests/lazy_objects/fetch_004.phpt create mode 100644 Zend/tests/lazy_objects/fetch_005.phpt create mode 100644 Zend/tests/lazy_objects/fetch_006.phpt create mode 100644 Zend/tests/lazy_objects/fetch_007.phpt create mode 100644 Zend/tests/lazy_objects/fetch_008.phpt create mode 100644 Zend/tests/lazy_objects/fetch_009.phpt create mode 100644 Zend/tests/lazy_objects/fetch_010.phpt create mode 100644 Zend/tests/lazy_objects/fetch_011.phpt create mode 100644 Zend/tests/lazy_objects/fetch_012.phpt create mode 100644 Zend/tests/lazy_objects/fetch_013.phpt create mode 100644 Zend/tests/lazy_objects/fetch_014.phpt create mode 100644 Zend/tests/lazy_objects/fetch_015.phpt create mode 100644 Zend/tests/lazy_objects/fetch_016.phpt create mode 100644 Zend/tests/lazy_objects/fetch_017.phpt create mode 100644 Zend/tests/lazy_objects/fetch_018.phpt create mode 100644 Zend/tests/lazy_objects/gc_001.phpt create mode 100644 Zend/tests/lazy_objects/gc_002.phpt create mode 100644 Zend/tests/lazy_objects/gc_003.phpt create mode 100644 Zend/tests/lazy_objects/gc_004.phpt create mode 100644 Zend/tests/lazy_objects/gc_005.phpt create mode 100644 Zend/tests/lazy_objects/get_initializer.phpt create mode 100644 Zend/tests/lazy_objects/ghost_001.phpt create mode 100644 Zend/tests/lazy_objects/ghost_002.phpt create mode 100644 Zend/tests/lazy_objects/init_exception_001.phpt create mode 100644 Zend/tests/lazy_objects/init_exception_002.phpt create mode 100644 Zend/tests/lazy_objects/init_exception_003.phpt create mode 100644 Zend/tests/lazy_objects/init_exception_005.phpt create mode 100644 Zend/tests/lazy_objects/init_exception_006.phpt create mode 100644 Zend/tests/lazy_objects/init_exception_009.phpt create mode 100644 Zend/tests/lazy_objects/init_exception_010.phpt create mode 100644 Zend/tests/lazy_objects/init_exception_011.phpt create mode 100644 Zend/tests/lazy_objects/init_exception_012.phpt create mode 100644 Zend/tests/lazy_objects/initialize_001.phpt create mode 100644 Zend/tests/lazy_objects/initialize_002.phpt create mode 100644 Zend/tests/lazy_objects/initialize_005.phpt create mode 100644 Zend/tests/lazy_objects/is_initialized_001.phpt create mode 100644 Zend/tests/lazy_objects/is_uninitialized_lazy_object.phpt create mode 100644 Zend/tests/lazy_objects/isset_001.phpt create mode 100644 Zend/tests/lazy_objects/isset_002.phpt create mode 100644 Zend/tests/lazy_objects/isset_003.phpt create mode 100644 Zend/tests/lazy_objects/make_lazy_already_exception.phpt create mode 100644 Zend/tests/lazy_objects/make_lazy_destructor_001.phpt create mode 100644 Zend/tests/lazy_objects/make_lazy_destructor_002.phpt create mode 100644 Zend/tests/lazy_objects/make_lazy_destructor_003.phpt create mode 100644 Zend/tests/lazy_objects/mark_as_initialized_001.phpt create mode 100644 Zend/tests/lazy_objects/new_instance_lazy_001.phpt create mode 100644 Zend/tests/lazy_objects/new_instance_lazy_002.phpt create mode 100644 Zend/tests/lazy_objects/new_instance_lazy_003.phpt create mode 100644 Zend/tests/lazy_objects/new_instance_lazy_004.phpt create mode 100644 Zend/tests/lazy_objects/new_instance_lazy_005.phpt create mode 100644 Zend/tests/lazy_objects/object_with_ast_const_001.phpt create mode 100644 Zend/tests/lazy_objects/object_with_ast_const_002.phpt create mode 100644 Zend/tests/lazy_objects/props_of_proxy_must_not_be_lazy_004.phpt create mode 100644 Zend/tests/lazy_objects/realize_001.phpt create mode 100644 Zend/tests/lazy_objects/realize_002.phpt create mode 100644 Zend/tests/lazy_objects/realize_003.phpt create mode 100644 Zend/tests/lazy_objects/reflection_lazy_object_skip_property_001.phpt create mode 100644 Zend/tests/lazy_objects/reflection_to_string_does_not_init.phpt create mode 100644 Zend/tests/lazy_objects/reset_as_lazy_can_reset_initialized_proxies.phpt create mode 100644 Zend/tests/lazy_objects/reset_as_lazy_ignores_additional_props.phpt create mode 100644 Zend/tests/lazy_objects/reset_readonly_001.phpt create mode 100644 Zend/tests/lazy_objects/rfc_example_001.phpt create mode 100644 Zend/tests/lazy_objects/rfc_example_002.phpt create mode 100644 Zend/tests/lazy_objects/rfc_example_003.phpt create mode 100644 Zend/tests/lazy_objects/rfc_example_004.phpt create mode 100644 Zend/tests/lazy_objects/rfc_example_005.phpt create mode 100644 Zend/tests/lazy_objects/rfc_example_006.phpt create mode 100644 Zend/tests/lazy_objects/rfc_example_007.phpt create mode 100644 Zend/tests/lazy_objects/rfc_example_008.phpt create mode 100644 Zend/tests/lazy_objects/rfc_example_009.phpt create mode 100644 Zend/tests/lazy_objects/rfc_example_010.phpt create mode 100644 Zend/tests/lazy_objects/rfc_example_011.phpt create mode 100644 Zend/tests/lazy_objects/rfc_example_012.phpt create mode 100644 Zend/tests/lazy_objects/serialize_001.phpt create mode 100644 Zend/tests/lazy_objects/serialize_002.phpt create mode 100644 Zend/tests/lazy_objects/serialize_003.phpt create mode 100644 Zend/tests/lazy_objects/serialize_004.phpt create mode 100644 Zend/tests/lazy_objects/serialize_005.phpt create mode 100644 Zend/tests/lazy_objects/serialize_006.phpt create mode 100644 Zend/tests/lazy_objects/serialize_007.phpt create mode 100644 Zend/tests/lazy_objects/serialize_008.phpt create mode 100644 Zend/tests/lazy_objects/serialize_009.phpt create mode 100644 Zend/tests/lazy_objects/serialize_010.phpt create mode 100644 Zend/tests/lazy_objects/set_raw_value_001.phpt create mode 100644 Zend/tests/lazy_objects/set_raw_value_002.phpt create mode 100644 Zend/tests/lazy_objects/set_raw_value_003.phpt create mode 100644 Zend/tests/lazy_objects/set_raw_value_004.phpt create mode 100644 Zend/tests/lazy_objects/set_raw_value_005.phpt create mode 100644 Zend/tests/lazy_objects/set_raw_value_006.phpt create mode 100644 Zend/tests/lazy_objects/set_raw_value_007.phpt create mode 100644 Zend/tests/lazy_objects/set_raw_value_008.phpt create mode 100644 Zend/tests/lazy_objects/set_raw_value_009.phpt create mode 100644 Zend/tests/lazy_objects/skip_initialization_001.phpt create mode 100644 Zend/tests/lazy_objects/skip_initialization_002.phpt create mode 100644 Zend/tests/lazy_objects/skip_initialization_003.phpt create mode 100644 Zend/tests/lazy_objects/skip_initialization_004.phpt create mode 100644 Zend/tests/lazy_objects/skip_initialization_005.phpt create mode 100644 Zend/tests/lazy_objects/skip_initialization_006.phpt create mode 100644 Zend/tests/lazy_objects/skip_initialization_007.phpt create mode 100644 Zend/tests/lazy_objects/skip_initialization_008.phpt create mode 100644 Zend/tests/lazy_objects/skip_initialization_009.phpt create mode 100644 Zend/tests/lazy_objects/skip_initialization_010.phpt create mode 100644 Zend/tests/lazy_objects/unclean_shutdown.phpt create mode 100644 Zend/tests/lazy_objects/unset_001.phpt create mode 100644 Zend/tests/lazy_objects/unset_003.phpt create mode 100644 Zend/tests/lazy_objects/unset_004.phpt create mode 100644 Zend/tests/lazy_objects/unset_005.phpt create mode 100644 Zend/tests/lazy_objects/unset_006.phpt create mode 100644 Zend/tests/lazy_objects/unset_007.phpt create mode 100644 Zend/tests/lazy_objects/unset_008.phpt create mode 100644 Zend/tests/lazy_objects/unset_009.phpt create mode 100644 Zend/tests/lazy_objects/unset_010.phpt create mode 100644 Zend/tests/lazy_objects/use_case_001.phpt create mode 100644 Zend/tests/lazy_objects/use_case_001b.phpt create mode 100644 Zend/tests/lazy_objects/use_case_002.phpt create mode 100644 Zend/tests/lazy_objects/write_001.phpt create mode 100644 Zend/tests/lazy_objects/write_002.phpt create mode 100644 Zend/tests/lazy_objects/write_003.phpt create mode 100644 Zend/tests/lazy_objects/write_004.phpt create mode 100644 Zend/tests/lazy_objects/write_005.phpt create mode 100644 Zend/tests/lazy_objects/write_006.phpt create mode 100644 Zend/zend_lazy_objects.c create mode 100644 Zend/zend_lazy_objects.h diff --git a/Zend/tests/lazy_objects/003.phpt b/Zend/tests/lazy_objects/003.phpt new file mode 100644 index 0000000000000..589f5535a7324 --- /dev/null +++ b/Zend/tests/lazy_objects/003.phpt @@ -0,0 +1,65 @@ +--TEST-- +Lazy objects: readonly properties can be lazily initialized +--FILE-- +a = 1; + } +} + +print "# Ghost:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +var_dump($obj); +var_dump($obj->a); +var_dump($obj); + +print "# Virtual:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +var_dump($obj); +var_dump($obj->a); +var_dump($obj->a); +var_dump($obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +int(1) +object(C)#%d (1) { + ["a"]=> + int(1) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +int(1) +int(1) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["a"]=> + int(1) + } +} diff --git a/Zend/tests/lazy_objects/004.phpt b/Zend/tests/lazy_objects/004.phpt new file mode 100644 index 0000000000000..bc71f687f05d7 --- /dev/null +++ b/Zend/tests/lazy_objects/004.phpt @@ -0,0 +1,65 @@ +--TEST-- +Lazy objects: readonly classes can be lazily initialized +--FILE-- +a = 1; + } +} + +print "# Ghost:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +var_dump($obj); +var_dump($obj->a); +var_dump($obj); + +print "# Virtual:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +var_dump($obj); +var_dump($obj->a); +var_dump($obj->a); +var_dump($obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +int(1) +object(C)#%d (1) { + ["a"]=> + int(1) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +int(1) +int(1) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["a"]=> + int(1) + } +} diff --git a/Zend/tests/lazy_objects/005.phpt b/Zend/tests/lazy_objects/005.phpt new file mode 100644 index 0000000000000..050b55871e2d1 --- /dev/null +++ b/Zend/tests/lazy_objects/005.phpt @@ -0,0 +1,164 @@ +--TEST-- +Lazy objects: initializer must return the right type +--FILE-- +b = 1; + } + public function __destruct() { + } +} + +class C extends B { +} + +class D extends C { + public int $b; // override +} + +class E extends B { + public function __destruct() { // override + } +} + +print "# Ghost initializer must return NULL or no value:\n"; + +$obj = (new ReflectionClass(C::class))->newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->__construct(); + return new stdClass; +}); + +var_dump($obj); +try { + var_dump($obj->a); +} catch (\Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} +var_dump($obj); + +print "# Virtual initializer must return an instance of a compatible class:\n"; +print "## Valid cases:\n"; + +$tests = [ + [C::class, new C()], + [C::class, new B()], + [D::class, new B()], +]; + +foreach ($tests as [$class, $instance]) { + $reflector = new ReflectionClass($class); + $obj = $reflector->newLazyProxy(function ($obj) use ($instance) { + var_dump("initializer"); + $instance->b = 1; + return $instance; + }); + + printf("## %s vs %s\n", get_class($obj), is_object($instance) ? get_class($instance) : gettype($instance)); + var_dump($obj->b); + var_dump($obj); +} + +print "## Invalid cases:\n"; + +$tests = [ + [C::class, new stdClass], + [C::class, new DateTime()], + [C::class, null], + [C::class, new D()], + [E::class, new B()], +]; + +foreach ($tests as [$class, $instance]) { + $obj = (new ReflectionClass($class))->newInstanceWithoutConstructor(); + (new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) use ($instance) { + var_dump("initializer"); + return $instance; + }); + + try { + printf("## %s vs %s\n", get_class($obj), is_object($instance) ? get_class($instance) : gettype($instance)); + var_dump($obj->a); + } catch (\Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } +} + +$obj = (new ReflectionClass(C::class))->newLazyProxy(function ($obj) { + var_dump("initializer"); + return $obj; +}); + +try { + printf("## %s vs itself\n", get_class($obj)); + var_dump($obj->a); +} catch (\Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +--EXPECTF-- +# Ghost initializer must return NULL or no value: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +TypeError: Lazy object initializer must return NULL or no value +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +# Virtual initializer must return an instance of a compatible class: +## Valid cases: +## C vs C +string(11) "initializer" +int(1) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["b"]=> + int(1) + } +} +## C vs B +string(11) "initializer" +int(1) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(B)#%d (1) { + ["b"]=> + int(1) + } +} +## D vs B +string(11) "initializer" +int(1) +lazy proxy object(D)#%d (1) { + ["instance"]=> + object(B)#%d (1) { + ["b"]=> + int(1) + } +} +## Invalid cases: +## C vs stdClass +string(11) "initializer" +TypeError: The real instance class stdClass is not compatible with the proxy class C. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor or __clone methods. +## C vs DateTime +string(11) "initializer" +TypeError: The real instance class DateTime is not compatible with the proxy class C. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor or __clone methods. +## C vs NULL +string(11) "initializer" +TypeError: The real instance class null is not compatible with the proxy class C. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor or __clone methods. +## C vs D +string(11) "initializer" +TypeError: The real instance class D is not compatible with the proxy class C. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor or __clone methods. +## E vs B +string(11) "initializer" +TypeError: The real instance class B is not compatible with the proxy class E. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor or __clone methods. +## C vs itself +string(11) "initializer" +Error: Lazy proxy factory must return a non-lazy object diff --git a/Zend/tests/lazy_objects/006.phpt b/Zend/tests/lazy_objects/006.phpt new file mode 100644 index 0000000000000..43211fa38e117 --- /dev/null +++ b/Zend/tests/lazy_objects/006.phpt @@ -0,0 +1,48 @@ +--TEST-- +Lazy objects: Foreach initializes object +--FILE-- +a = 1; + } +} + +print "# Ghost:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +foreach ($obj as $prop => $value) { + var_dump($prop, $value); +} + +print "# Virtual:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +foreach ($obj as $prop => $value) { + var_dump($prop, $value); +} + +--EXPECTF-- +# Ghost: +string(11) "initializer" +string(14) "C::__construct" +string(1) "a" +int(1) +# Virtual: +string(11) "initializer" +string(14) "C::__construct" +string(1) "a" +int(1) diff --git a/Zend/tests/lazy_objects/007.phpt b/Zend/tests/lazy_objects/007.phpt new file mode 100644 index 0000000000000..6dfdf1457f4cf --- /dev/null +++ b/Zend/tests/lazy_objects/007.phpt @@ -0,0 +1,64 @@ +--TEST-- +Lazy objects: var_dump does not initialize object +--FILE-- +a = 1; + } +} + +$reflector = new ReflectionClass(C::class); + +print "# Ghost:\n"; + +$obj = $reflector->newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +var_dump($obj); +$reflector->initializeLazyObject($obj); +var_dump($obj); + +print "# Virtual:\n"; + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyProxy(function ($obj) { + var_dump("initializer"); + return new C(); +}); + +var_dump($obj); +$reflector->initializeLazyObject($obj); +var_dump($obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +object(C)#%d (1) { + ["a"]=> + int(1) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["a"]=> + int(1) + } +} diff --git a/Zend/tests/lazy_objects/008.phpt b/Zend/tests/lazy_objects/008.phpt new file mode 100644 index 0000000000000..56b1b30219b14 --- /dev/null +++ b/Zend/tests/lazy_objects/008.phpt @@ -0,0 +1,47 @@ +--TEST-- +Lazy objects: var_export initializes object +--FILE-- +a = 1; + } +} + +print "# Ghost:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +var_export($obj); +print "\n"; + +print "# Virtual:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +var_export($obj); +print "\n"; +--EXPECTF-- +# Ghost: +string(11) "initializer" +string(14) "C::__construct" +\C::__set_state(array( + 'a' => 1, +)) +# Virtual: +string(11) "initializer" +string(14) "C::__construct" +\C::__set_state(array( + 'a' => 1, +)) diff --git a/Zend/tests/lazy_objects/009.phpt b/Zend/tests/lazy_objects/009.phpt new file mode 100644 index 0000000000000..7f1263a50af70 --- /dev/null +++ b/Zend/tests/lazy_objects/009.phpt @@ -0,0 +1,43 @@ +--TEST-- +Lazy objects: serialize initializes object +--FILE-- +a = 1; + } +} + +print "# Ghost:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +var_dump(serialize($obj)); + +print "# Virtual:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +var_dump(serialize($obj)); + + +--EXPECTF-- +# Ghost: +string(11) "initializer" +string(14) "C::__construct" +string(24) "O:1:"C":1:{s:1:"a";i:1;}" +# Virtual: +string(11) "initializer" +string(14) "C::__construct" +string(24) "O:1:"C":1:{s:1:"a";i:1;}" diff --git a/Zend/tests/lazy_objects/010.phpt b/Zend/tests/lazy_objects/010.phpt new file mode 100644 index 0000000000000..ad996a5a21191 --- /dev/null +++ b/Zend/tests/lazy_objects/010.phpt @@ -0,0 +1,42 @@ +--TEST-- +Lazy objects: json_encode initializes object +--FILE-- +a = 1; + } +} + +print "# Ghost:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +var_dump(json_encode($obj)); + +print "# Virtual:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +var_dump(json_encode($obj)); + +--EXPECTF-- +# Ghost: +string(11) "initializer" +string(14) "C::__construct" +string(7) "{"a":1}" +# Virtual: +string(11) "initializer" +string(14) "C::__construct" +string(7) "{"a":1}" diff --git a/Zend/tests/lazy_objects/011.phpt b/Zend/tests/lazy_objects/011.phpt new file mode 100644 index 0000000000000..3636a53d19831 --- /dev/null +++ b/Zend/tests/lazy_objects/011.phpt @@ -0,0 +1,62 @@ +--TEST-- +Lazy objects: get_object_vars initializes object +--FILE-- +a = 1; + } +} + +print "# Ghost:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +var_dump(get_object_vars($obj)); + +$obj->a = 2; +var_dump(get_object_vars($obj)); + +print "# Virtual:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +var_dump(get_object_vars($obj)); + +$obj->a = 2; +var_dump(get_object_vars($obj)); + +--EXPECT-- +# Ghost: +string(11) "initializer" +string(14) "C::__construct" +array(1) { + ["a"]=> + int(1) +} +array(1) { + ["a"]=> + int(2) +} +# Virtual: +string(11) "initializer" +string(14) "C::__construct" +array(1) { + ["a"]=> + int(1) +} +array(1) { + ["a"]=> + int(2) +} diff --git a/Zend/tests/lazy_objects/012.phpt b/Zend/tests/lazy_objects/012.phpt new file mode 100644 index 0000000000000..ab8e5c5c3fcbe --- /dev/null +++ b/Zend/tests/lazy_objects/012.phpt @@ -0,0 +1,58 @@ +--TEST-- +Lazy objects: array cast does not initialize object +--FILE-- +a = 1; + } +} + +print "# Ghost:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +var_dump((array)$obj); + +$obj->a = 2; +var_dump((array)$obj); + +print "# Virtual:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +var_dump((array)$obj); + +$obj->a = 2; +var_dump((array)$obj); + +--EXPECTF-- +# Ghost: +array(0) { +} +string(11) "initializer" +string(14) "C::__construct" +array(1) { + ["a"]=> + int(2) +} +# Virtual: +array(0) { +} +string(11) "initializer" +string(14) "C::__construct" +array(1) { + ["a"]=> + int(2) +} diff --git a/Zend/tests/lazy_objects/013.phpt b/Zend/tests/lazy_objects/013.phpt new file mode 100644 index 0000000000000..8e92692169bc1 --- /dev/null +++ b/Zend/tests/lazy_objects/013.phpt @@ -0,0 +1,65 @@ +--TEST-- +Lazy objects: final classes can be initialized lazily +--FILE-- +a = 1; + } +} + +print "# Ghost:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +var_dump($obj); +var_dump($obj->a); +var_dump($obj); + +print "# Virtual:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +var_dump($obj); +var_dump($obj->a); +var_dump($obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +int(1) +object(C)#%d (1) { + ["a"]=> + int(1) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +int(1) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["a"]=> + int(1) + } +} diff --git a/Zend/tests/lazy_objects/014.phpt b/Zend/tests/lazy_objects/014.phpt new file mode 100644 index 0000000000000..ec16a8bf9571c --- /dev/null +++ b/Zend/tests/lazy_objects/014.phpt @@ -0,0 +1,34 @@ +--TEST-- +Lazy objects: internal classes can not be initialized lazily +--FILE-- +newInstanceWithoutConstructor(); +try { + (new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); + }); +} catch (Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +print "# Virtual:\n"; + +$obj = (new ReflectionClass(DateTime::class))->newInstanceWithoutConstructor(); +try { + (new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); + }); +} catch (Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +--EXPECTF-- +# Ghost: +Error: Cannot make instance of internal class lazy: DateTime is internal +# Virtual: +Error: Cannot make instance of internal class lazy: DateTime is internal diff --git a/Zend/tests/lazy_objects/015.phpt b/Zend/tests/lazy_objects/015.phpt new file mode 100644 index 0000000000000..727beb63ecb86 --- /dev/null +++ b/Zend/tests/lazy_objects/015.phpt @@ -0,0 +1,37 @@ +--TEST-- +Lazy objects: sub-classes of internal classes can not be initialized lazily +--FILE-- +newInstanceWithoutConstructor(); +try { + (new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); + }); +} catch (Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +print "# Virtual:\n"; + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +try { + (new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); + }); +} catch (Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +--EXPECTF-- +# Ghost: +Error: Cannot make instance of internal class lazy: C inherits internal class DateTime +# Virtual: +Error: Cannot make instance of internal class lazy: C inherits internal class DateTime diff --git a/Zend/tests/lazy_objects/016.phpt b/Zend/tests/lazy_objects/016.phpt new file mode 100644 index 0000000000000..5efd48bdebff1 --- /dev/null +++ b/Zend/tests/lazy_objects/016.phpt @@ -0,0 +1,45 @@ +--TEST-- +Lazy objects: destructor of lazy objets is not called if not initialized +--FILE-- +newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function () { + var_dump("initializer"); +}); +print "After makeLazy\n"; + +// Does not call destructor +$obj = null; + +print "# Virtual:\n"; + +print "In makeLazy\n"; +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function () { + var_dump("initializer"); +}); +print "After makeLazy\n"; + +// Does not call destructor +$obj = null; + +--EXPECT-- +# Ghost: +In makeLazy +string(13) "C::__destruct" +After makeLazy +# Virtual: +In makeLazy +string(13) "C::__destruct" +After makeLazy diff --git a/Zend/tests/lazy_objects/017.phpt b/Zend/tests/lazy_objects/017.phpt new file mode 100644 index 0000000000000..e5ebc8aa50ad5 --- /dev/null +++ b/Zend/tests/lazy_objects/017.phpt @@ -0,0 +1,74 @@ +--TEST-- +Lazy objects: destructor of initialized objets is called +--FILE-- +newInstanceWithoutConstructor(); + (new ReflectionClass($obj))->resetAsLazyGhost($obj, function () { + var_dump("initializer"); + }); + print "After makeLazy\n"; + + var_dump($obj->a); +} + +function virtual() { + print "# Virtual:\n"; + + print "In makeLazy\n"; + $obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); + (new ReflectionClass($obj))->resetAsLazyProxy($obj, function () { + var_dump("initializer"); + return new C(); + }); + print "After makeLazy\n"; + + var_dump($obj->a); +} + +ghost(); +virtual(); + +--EXPECTF-- +# Ghost: +In makeLazy +string(13) "C::__destruct" +object(C)#%d (1) { + ["a"]=> + int(1) +} +After makeLazy +string(11) "initializer" +int(1) +string(13) "C::__destruct" +object(C)#%d (1) { + ["a"]=> + int(1) +} +# Virtual: +In makeLazy +string(13) "C::__destruct" +object(C)#%d (1) { + ["a"]=> + int(1) +} +After makeLazy +string(11) "initializer" +int(1) +string(13) "C::__destruct" +object(C)#%d (1) { + ["a"]=> + int(1) +} diff --git a/Zend/tests/lazy_objects/018.phpt b/Zend/tests/lazy_objects/018.phpt new file mode 100644 index 0000000000000..2ee1b6e2db630 --- /dev/null +++ b/Zend/tests/lazy_objects/018.phpt @@ -0,0 +1,57 @@ +--TEST-- +Lazy objects: exception during initializer leaves object uninitialized +--FILE-- +a); + } catch (Exception $e) { + printf("%s\n", $e->getMessage()); + } + var_dump((new ReflectionClass($obj))->isUninitializedLazyObject($obj)); + try { + var_dump($obj->a); + } catch (Exception $e) { + printf("%s\n", $e->getMessage()); + } + var_dump((new ReflectionClass($obj))->isUninitializedLazyObject($obj)); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function () { + var_dump("initializer"); + throw new \Exception('initializer exception'); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function () { + var_dump("initializer"); + throw new \Exception('initializer exception'); +}); + +test('Virtual', $obj); + +--EXPECT-- +# Ghost: +string(11) "initializer" +initializer exception +bool(true) +string(11) "initializer" +initializer exception +bool(true) +# Virtual: +string(11) "initializer" +initializer exception +bool(true) +string(11) "initializer" +initializer exception +bool(true) diff --git a/Zend/tests/lazy_objects/019.phpt b/Zend/tests/lazy_objects/019.phpt new file mode 100644 index 0000000000000..819421f60afd4 --- /dev/null +++ b/Zend/tests/lazy_objects/019.phpt @@ -0,0 +1,56 @@ +--TEST-- +Lazy objects: get_mangled_object_vars does not initialize object +--FILE-- +a = 1; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump(get_mangled_object_vars($obj)); + + $obj->a = 2; + var_dump(get_mangled_object_vars($obj)); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); +--EXPECTF-- +# Ghost: +array(0) { +} +string(11) "initializer" +string(14) "C::__construct" +array(1) { + ["a"]=> + int(2) +} +# Virtual: +array(0) { +} +string(11) "initializer" +string(14) "C::__construct" +array(1) { + ["a"]=> + int(2) +} diff --git a/Zend/tests/lazy_objects/020.phpt b/Zend/tests/lazy_objects/020.phpt new file mode 100644 index 0000000000000..a05f9a32d00ff --- /dev/null +++ b/Zend/tests/lazy_objects/020.phpt @@ -0,0 +1,80 @@ +--TEST-- +Lazy objects: dymamic properties are unset when object is made lazy +--FILE-- +a = new Canary(); + } +} + +print "# Ghost:\n"; + +$obj = new C(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +var_dump($obj); +var_dump($obj->a); +var_dump($obj); + +print "# Virtual:\n"; + +$obj = new C(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +var_dump($obj); +var_dump($obj->a); +var_dump($obj->a); +var_dump($obj); + +--EXPECTF-- +# Ghost: +string(18) "Canary::__destruct" +lazy ghost object(C)#%d (0) { +} +string(11) "initializer" +object(Canary)#%d (0) { +} +object(C)#%d (2) { + ["b"]=> + NULL + ["a"]=> + object(Canary)#%d (0) { + } +} +# Virtual: +string(18) "Canary::__destruct" +string(18) "Canary::__destruct" +lazy proxy object(C)#%d (0) { +} +string(11) "initializer" +object(Canary)#%d (0) { +} +object(Canary)#%d (0) { +} +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["b"]=> + NULL + ["a"]=> + object(Canary)#%d (0) { + } + } +} +string(18) "Canary::__destruct" diff --git a/Zend/tests/lazy_objects/021.phpt b/Zend/tests/lazy_objects/021.phpt new file mode 100644 index 0000000000000..c4cc63c4a9743 --- /dev/null +++ b/Zend/tests/lazy_objects/021.phpt @@ -0,0 +1,81 @@ +--TEST-- +Lazy objects: reference source type is deleted by makeLazy() +--FILE-- +a = 1; + } +} + +print "# Ghost:\n"; + +$obj = new C(); +$ref = &$obj->a; +try { + $ref = 'string'; +} catch (\Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +$ref = 'string'; +var_dump($obj); +var_dump($obj->a); +var_dump($obj); + +print "# Virtual:\n"; + +$obj = new C(); +$ref = &$obj->a; +try { + $ref = 'string'; +} catch (\Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +$ret = 'string'; +var_dump($obj); +var_dump($obj->a); +var_dump($obj->a); +var_dump($obj); + +--EXPECTF-- +# Ghost: +TypeError: Cannot assign string to reference held by property C::$a of type int +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +int(1) +object(C)#%d (1) { + ["a"]=> + int(1) +} +# Virtual: +TypeError: Cannot assign string to reference held by property C::$a of type int +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +int(1) +int(1) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["a"]=> + int(1) + } +} diff --git a/Zend/tests/lazy_objects/024.phpt b/Zend/tests/lazy_objects/024.phpt new file mode 100644 index 0000000000000..548088394a650 --- /dev/null +++ b/Zend/tests/lazy_objects/024.phpt @@ -0,0 +1,36 @@ +--TEST-- +Lazy objects: fatal error during initialization of ghost object +--FILE-- +newInstanceWithoutConstructor(); +$reflector->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +$reflector->getProperty('b')->setRawValueWithoutLazyInitialization($obj, new stdClass); + +var_dump($obj); +var_dump($obj->c); +var_dump($obj); + +--EXPECTF-- +lazy ghost object(C)#%d (1) { + ["b"]=> + object(stdClass)#%d (0) { + } +} +string(11) "initializer" + +Parse error: Unclosed '{' in %s on line %d diff --git a/Zend/tests/lazy_objects/025.phpt b/Zend/tests/lazy_objects/025.phpt new file mode 100644 index 0000000000000..3f101dc5a2060 --- /dev/null +++ b/Zend/tests/lazy_objects/025.phpt @@ -0,0 +1,55 @@ +--TEST-- +Lazy objects: var_dump may not initialize object with __debugInfo() method +--FILE-- +a = 1; + } + public function __debugInfo() { + return ['hello']; + } +} + +function test(string $name, object $obj) { + printf("# %s\n", $name); + + var_dump($obj); + printf("Initialized:\n"); + var_dump(!(new ReflectionClass($obj))->isUninitializedLazyObject($obj)); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost +lazy ghost object(C)#%d (1) { + [0]=> + string(5) "hello" +} +Initialized: +bool(false) +# Virtual +lazy proxy object(C)#%d (1) { + [0]=> + string(5) "hello" +} +Initialized: +bool(false) diff --git a/Zend/tests/lazy_objects/026.phpt b/Zend/tests/lazy_objects/026.phpt new file mode 100644 index 0000000000000..aea4a5003cf0c --- /dev/null +++ b/Zend/tests/lazy_objects/026.phpt @@ -0,0 +1,59 @@ +--TEST-- +Lazy objects: var_dump may initialize object with __debugInfo() method +--FILE-- +a = 1; + } + public function __debugInfo() { + return [$this->a]; + } +} + +function test(string $name, object $obj) { + printf("# %s\n", $name); + + var_dump($obj); + printf("Initialized:\n"); + var_dump(!(new ReflectionClass($obj))->isUninitializedLazyObject($obj)); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost +string(11) "initializer" +string(14) "C::__construct" +object(C)#%d (1) { + [0]=> + int(1) +} +Initialized: +bool(true) +# Virtual +string(11) "initializer" +string(14) "C::__construct" +lazy proxy object(C)#%d (1) { + [0]=> + int(1) +} +Initialized: +bool(true) diff --git a/Zend/tests/lazy_objects/027.phpt b/Zend/tests/lazy_objects/027.phpt new file mode 100644 index 0000000000000..0909942bcb284 --- /dev/null +++ b/Zend/tests/lazy_objects/027.phpt @@ -0,0 +1,63 @@ +--TEST-- +Lazy objects: debug_zval_dump does not initialize object +--FILE-- +a = 1; + } +} + +$reflector = new ReflectionClass(C::class); + +print "# Ghost:\n"; + +$obj = $reflector->newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +debug_zval_dump($obj); +$reflector->initializeLazyObject($obj); +debug_zval_dump($obj); + +print "# Virtual:\n"; + +$obj = $reflector->newLazyProxy(function ($obj) { + var_dump("initializer"); + return new C(); +}); + +debug_zval_dump($obj); +$reflector->initializeLazyObject($obj); +debug_zval_dump($obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) refcount(2){ + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +object(C)#%d (1) refcount(2){ + ["a"]=> + int(1) +} +# Virtual: +lazy proxy object(C)#%d (0) refcount(2){ + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +lazy proxy object(C)#%d (1) refcount(2){ + ["instance"]=> + object(C)#%d (1) refcount(2){ + ["a"]=> + int(1) + } +} diff --git a/Zend/tests/lazy_objects/clone_001.phpt b/Zend/tests/lazy_objects/clone_001.phpt new file mode 100644 index 0000000000000..c7ca01ba1168b --- /dev/null +++ b/Zend/tests/lazy_objects/clone_001.phpt @@ -0,0 +1,71 @@ +--TEST-- +Lazy objects: clone initializes object +--FILE-- +isUninitializedLazyObject($obj)); + var_dump($obj); + var_dump($reflector->isUninitializedLazyObject($clone)); + var_dump($clone); +} + +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +string(11) "initializer" +bool(false) +object(C)#%d (1) { + ["a"]=> + int(1) +} +bool(false) +object(C)#%d (1) { + ["a"]=> + int(1) +} +# Virtual: +string(11) "initializer" +bool(false) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["a"]=> + int(1) + } +} +bool(false) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["a"]=> + int(1) + } +} diff --git a/Zend/tests/lazy_objects/clone_002.phpt b/Zend/tests/lazy_objects/clone_002.phpt new file mode 100644 index 0000000000000..f2af4b241250e --- /dev/null +++ b/Zend/tests/lazy_objects/clone_002.phpt @@ -0,0 +1,77 @@ +--TEST-- +Lazy objects: clone calls __clone() once +--FILE-- +isUninitializedLazyObject($obj)); + var_dump($obj); + var_dump($reflector->isUninitializedLazyObject($clone)); + var_dump($clone); +} + +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +string(11) "initializer" +string(5) "clone" +bool(false) +object(C)#%d (1) { + ["a"]=> + int(1) +} +bool(false) +object(C)#%d (1) { + ["a"]=> + int(1) +} +# Virtual: +string(11) "initializer" +string(5) "clone" +bool(false) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["a"]=> + int(1) + } +} +bool(false) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["a"]=> + int(1) + } +} diff --git a/Zend/tests/lazy_objects/clone_003.phpt b/Zend/tests/lazy_objects/clone_003.phpt new file mode 100644 index 0000000000000..8334e6eadd84e --- /dev/null +++ b/Zend/tests/lazy_objects/clone_003.phpt @@ -0,0 +1,56 @@ +--TEST-- +Lazy objects: clone: initializer exception +--FILE-- +getMessage()); + } + + var_dump($reflector->isUninitializedLazyObject($obj)); + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { + throw new \Exception('initializer'); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function ($obj) { + throw new \Exception('initializer'); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +Exception: initializer +bool(true) +lazy ghost object(C)#%d (0) { +} +# Virtual: +Exception: initializer +bool(true) +lazy proxy object(C)#%d (0) { +} diff --git a/Zend/tests/lazy_objects/clone_004.phpt b/Zend/tests/lazy_objects/clone_004.phpt new file mode 100644 index 0000000000000..30f802a7fd5f3 --- /dev/null +++ b/Zend/tests/lazy_objects/clone_004.phpt @@ -0,0 +1,73 @@ +--TEST-- +Lazy objects: clone of initialized lazy object does not initialize twice +--FILE-- +initializeLazyObject($obj); + + $clone = clone $obj; + + var_dump($reflector->isUninitializedLazyObject($obj)); + var_dump($obj); + var_dump($reflector->isUninitializedLazyObject($clone)); + var_dump($clone); +} + +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +string(11) "initializer" +bool(false) +object(C)#%d (1) { + ["a"]=> + int(1) +} +bool(false) +object(C)#%d (1) { + ["a"]=> + int(1) +} +# Virtual: +string(11) "initializer" +bool(false) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["a"]=> + int(1) + } +} +bool(false) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["a"]=> + int(1) + } +} diff --git a/Zend/tests/lazy_objects/clone_007.phpt b/Zend/tests/lazy_objects/clone_007.phpt new file mode 100644 index 0000000000000..9a350e6f01cd8 --- /dev/null +++ b/Zend/tests/lazy_objects/clone_007.phpt @@ -0,0 +1,35 @@ +--TEST-- +Lazy objects: clone semantics +--FILE-- +newLazyProxy($initializer); +$reflector->getProperty('foo')->skipLazyInitialization($myProxy); + +$clonedProxy = clone $myProxy; +var_dump($clonedProxy->foo); + +$reflector->initializeLazyObject($myProxy); +$myProxy->foo = 'B'; + +$reflector->initializeLazyObject($clonedProxy); + +var_dump($myProxy->foo); +var_dump($clonedProxy->foo); + +--EXPECT-- +string(1) "A" +string(1) "B" +string(1) "A" diff --git a/Zend/tests/lazy_objects/clone_008.phpt b/Zend/tests/lazy_objects/clone_008.phpt new file mode 100644 index 0000000000000..7d0a73b135197 --- /dev/null +++ b/Zend/tests/lazy_objects/clone_008.phpt @@ -0,0 +1,56 @@ +--TEST-- +Lazy objects: clone semantics +--FILE-- +value = new Value(); + } + public function __clone() { + $this->value = clone $this->value; + } +} + +class Value { + public string $value = 'A'; +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + $reflector = new ReflectionClass(SomeObj::class); + + $clonedObj = clone $obj; + var_dump($clonedObj->value->value); + + $reflector->initializeLazyObject($obj); + $obj->value->value = 'B'; + + $reflector->initializeLazyObject($clonedObj); + + var_dump($obj->value->value); + var_dump($clonedObj->value->value); +} + +$reflector = new ReflectionClass(SomeObj::class); + +test('Ghost', $reflector->newLazyGhost(function ($obj) { + $obj->__construct(); +})); + +test('Proxy', $reflector->newLazyProxy(function () { + return new SomeObj(); +})); + +?> +--EXPECT-- +# Ghost: +string(1) "A" +string(1) "B" +string(1) "A" +# Proxy: +string(1) "A" +string(1) "B" +string(1) "A" diff --git a/Zend/tests/lazy_objects/clone_009.phpt b/Zend/tests/lazy_objects/clone_009.phpt new file mode 100644 index 0000000000000..3afad3e8104c1 --- /dev/null +++ b/Zend/tests/lazy_objects/clone_009.phpt @@ -0,0 +1,40 @@ +--TEST-- +Lazy objects: clone semantics +--FILE-- +initializeLazyObject($obj); + $reflector->getProperty('foo')->setRawValueWithoutLazyInitialization($clonedObj, 'Y'); + + $reflector->initializeLazyObject($clonedObj); + + var_dump($clonedObj->foo); +} + +$reflector = new ReflectionClass(SomeObj::class); + +test('Ghost', $reflector->newLazyGhost(function ($obj) { +})); + +test('Proxy', $reflector->newLazyProxy(function () { + return new SomeObj(); +})); + +?> +--EXPECT-- +# Ghost: +string(1) "Y" +# Proxy: +string(1) "Y" diff --git a/Zend/tests/lazy_objects/feedback_001.phpt b/Zend/tests/lazy_objects/feedback_001.phpt new file mode 100644 index 0000000000000..f33549b84922a --- /dev/null +++ b/Zend/tests/lazy_objects/feedback_001.phpt @@ -0,0 +1,49 @@ +--TEST-- +Lazy objects: feedback 001 +--FILE-- +foo = new Foo(); + +$reflector = new ReflectionClass(Bar::class); + +print "Reset\n"; + +$reflector->resetAsLazyProxy($bar, function (Bar $bar) { + $result = new Bar(); + $result->foo = null; + $result->s = 'init'; + return $result; +}); + +print "Dump\n"; + +var_dump($bar->s); + +print "Done\n"; + +?> +--EXPECT-- +Reset +Bar::__destruct +Foo::__destruct +Dump +string(4) "init" +Done +Bar::__destruct diff --git a/Zend/tests/lazy_objects/feedback_002.phpt b/Zend/tests/lazy_objects/feedback_002.phpt new file mode 100644 index 0000000000000..76138e8656a75 --- /dev/null +++ b/Zend/tests/lazy_objects/feedback_002.phpt @@ -0,0 +1,36 @@ +--TEST-- +Lazy objects: feedback 002 +--FILE-- +foo = $this; + var_dump(__METHOD__); + } + public function __destruct() { + var_dump(__METHOD__); + } +} + +$reflector = new ReflectionClass(Foo::class); +$foo = $reflector->newLazyGhost(new Initializer()); + +print "Dump\n"; + +var_dump($foo->foo); + +print "Done\n"; + +?> +--EXPECTF-- +Dump +string(21) "Initializer::__invoke" +object(Initializer)#%d (0) { +} +Done +string(23) "Initializer::__destruct" diff --git a/Zend/tests/lazy_objects/feedback_003.phpt b/Zend/tests/lazy_objects/feedback_003.phpt new file mode 100644 index 0000000000000..e3b16703fdf23 --- /dev/null +++ b/Zend/tests/lazy_objects/feedback_003.phpt @@ -0,0 +1,33 @@ +--TEST-- +Lazy objects: feedback 003 +--FILE-- +newLazyProxy(function (B $o) { + return new A(); +}); + +var_dump(get_class($o)); +$o->foo(); +$o->s = 'init'; +var_dump(get_class($o)); +$o->foo(); + + +?> +--EXPECT-- +string(1) "B" +string(6) "B::foo" +string(1) "B" +string(6) "B::foo" diff --git a/Zend/tests/lazy_objects/feedback_004.phpt b/Zend/tests/lazy_objects/feedback_004.phpt new file mode 100644 index 0000000000000..fb6d2e31fe0e0 --- /dev/null +++ b/Zend/tests/lazy_objects/feedback_004.phpt @@ -0,0 +1,29 @@ +--TEST-- +Lazy objects: feedback 004 +--FILE-- +resetAsLazyProxy($object, function (MyObject $object) use (&$object2Id) { + $object2 = new MyObject(); + $object2Id = spl_object_id($object2); + return $object2; +}); +var_dump(spl_object_id($object) === $objectId); +$reflector->initializeLazyObject($object); +var_dump(spl_object_id($object) === $objectId); +var_dump(spl_object_id($object) !== $object2Id); + +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) diff --git a/Zend/tests/lazy_objects/feedback_005.phpt b/Zend/tests/lazy_objects/feedback_005.phpt new file mode 100644 index 0000000000000..83454e70a7c96 --- /dev/null +++ b/Zend/tests/lazy_objects/feedback_005.phpt @@ -0,0 +1,50 @@ +--TEST-- +Lazy objects: feedback 005 +--FILE-- +newLazyGhost(function ($c) { + $c->c = 1; +}); + +$b = $bReflector->newLazyGhost(function () { + throw new \Exception('xxx'); +}); + +$a = $aReflector->newLazyGhost(function ($a) use ($b, $c) { + $a->a = $c->c + $b->b; +}); + +try { + $a->init = 'please'; +} catch (\Exception $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +var_dump($a, $b, $c); + +?> +--EXPECTF-- +Exception: xxx +lazy ghost object(A)#%d (0) { +} +lazy ghost object(B)#%d (0) { +} +object(C)#%d (1) { + ["c"]=> + int(1) +} diff --git a/Zend/tests/lazy_objects/feedback_006.phpt b/Zend/tests/lazy_objects/feedback_006.phpt new file mode 100644 index 0000000000000..64d1ae00938e3 --- /dev/null +++ b/Zend/tests/lazy_objects/feedback_006.phpt @@ -0,0 +1,29 @@ +--TEST-- +Lazy objects: feedback 006 +--FILE-- +foo; + } +} + +$r = new ReflectionClass(B::class); +$obj = $r->newLazyProxy(function ($obj) { + return new A(); +}); + +try { + $obj->getFoo(); +} catch (\Throwable $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +?> +--EXPECT-- +TypeError: The real instance class A is not compatible with the proxy class B. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor or __clone methods. diff --git a/Zend/tests/lazy_objects/feedback_007.phpt b/Zend/tests/lazy_objects/feedback_007.phpt new file mode 100644 index 0000000000000..f59e56b2fd500 --- /dev/null +++ b/Zend/tests/lazy_objects/feedback_007.phpt @@ -0,0 +1,31 @@ +--TEST-- +Lazy objects: feedback 007 +--FILE-- +foo(); } + +$r = new ReflectionClass(B::class); +$b = $r->newLazyProxy(function ($obj) { + return new A('value'); +}); + +$b->property = 'init_please'; + +$clone = clone $b; +only_b($b); +only_b($clone); + +?> +==DONE== +--EXPECT-- +==DONE== diff --git a/Zend/tests/lazy_objects/feedback_008.phpt b/Zend/tests/lazy_objects/feedback_008.phpt new file mode 100644 index 0000000000000..d309a2cd67d91 --- /dev/null +++ b/Zend/tests/lazy_objects/feedback_008.phpt @@ -0,0 +1,53 @@ +--TEST-- +Lazy objects: feedback 008 +--FILE-- +resetAsLazyProxy($obj, function () { + return new Obj('obj2'); +}); +$r->initializeLazyObject($obj); +var_dump($obj); +$r->resetAsLazyProxy($obj, function () { + return new Obj('obj3'); +}); +var_dump($obj); +$r->initializeLazyObject($obj); +var_dump($obj); + +?> +==DONE== +--EXPECTF-- +object(Obj)#%d (1) { + ["name"]=> + string(4) "obj1" +} +lazy proxy object(Obj)#%d (1) { + ["instance"]=> + object(Obj)#%d (1) { + ["name"]=> + string(4) "obj2" + } +} +lazy proxy object(Obj)#%d (0) { + ["name"]=> + uninitialized(string) +} +lazy proxy object(Obj)#%d (1) { + ["instance"]=> + object(Obj)#%d (1) { + ["name"]=> + string(4) "obj3" + } +} +==DONE== diff --git a/Zend/tests/lazy_objects/feedback_009.phpt b/Zend/tests/lazy_objects/feedback_009.phpt new file mode 100644 index 0000000000000..f5da04cd6d320 --- /dev/null +++ b/Zend/tests/lazy_objects/feedback_009.phpt @@ -0,0 +1,29 @@ +--TEST-- +Lazy objects: feedback 009 +--FILE-- +resetAsLazyProxy($obj1, function () use (&$obj2) { + $obj2 = new Obj('obj2'); + return $obj2; +}); +$r->initializeLazyObject($obj1); +$r->resetAsLazyProxy($obj2, function () { + return new Obj('obj3'); +}); +var_dump($obj1->name); + +?> +==DONE== +--EXPECT-- +string(4) "obj3" +==DONE== diff --git a/Zend/tests/lazy_objects/fetch_001.phpt b/Zend/tests/lazy_objects/fetch_001.phpt new file mode 100644 index 0000000000000..d89cba11d4481 --- /dev/null +++ b/Zend/tests/lazy_objects/fetch_001.phpt @@ -0,0 +1,72 @@ +--TEST-- +Lazy objects: property fetch initializes object +--FILE-- +a = $a; + $this->b = 2; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + var_dump($obj->a); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(1); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(1); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +int(1) +object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + int(2) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +int(1) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + int(2) + } +} diff --git a/Zend/tests/lazy_objects/fetch_002.phpt b/Zend/tests/lazy_objects/fetch_002.phpt new file mode 100644 index 0000000000000..fda287265948e --- /dev/null +++ b/Zend/tests/lazy_objects/fetch_002.phpt @@ -0,0 +1,65 @@ +--TEST-- +Lazy objects: property fetch of dynamic property initializes object +--FILE-- +dynamic); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +NULL +object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +NULL +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (0) { + ["a"]=> + uninitialized(int) + } +} diff --git a/Zend/tests/lazy_objects/fetch_003.phpt b/Zend/tests/lazy_objects/fetch_003.phpt new file mode 100644 index 0000000000000..d24af36221a0f --- /dev/null +++ b/Zend/tests/lazy_objects/fetch_003.phpt @@ -0,0 +1,65 @@ +--TEST-- +Lazy objects: property op initializes object +--FILE-- +a = 2; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + var_dump($obj->a++); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +int(2) +object(C)#%d (1) { + ["a"]=> + int(3) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +int(2) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%s (1) { + ["a"]=> + int(3) + } +} diff --git a/Zend/tests/lazy_objects/fetch_004.phpt b/Zend/tests/lazy_objects/fetch_004.phpt new file mode 100644 index 0000000000000..892850fed5f0f --- /dev/null +++ b/Zend/tests/lazy_objects/fetch_004.phpt @@ -0,0 +1,69 @@ +--TEST-- +Lazy objects: dynamic property op initializes object +--FILE-- +dynamic++); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +NULL +object(C)#%d (2) { + ["a"]=> + int(1) + ["dynamic"]=> + int(1) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +NULL +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["a"]=> + int(1) + ["dynamic"]=> + int(1) + } +} diff --git a/Zend/tests/lazy_objects/fetch_005.phpt b/Zend/tests/lazy_objects/fetch_005.phpt new file mode 100644 index 0000000000000..11b8d463ced95 --- /dev/null +++ b/Zend/tests/lazy_objects/fetch_005.phpt @@ -0,0 +1,60 @@ +--TEST-- +Lazy objects: magic property fetch may not initialize object +--FILE-- +magic); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(5) "magic" +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(5) "magic" +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} diff --git a/Zend/tests/lazy_objects/fetch_006.phpt b/Zend/tests/lazy_objects/fetch_006.phpt new file mode 100644 index 0000000000000..ecf5ab123b4bf --- /dev/null +++ b/Zend/tests/lazy_objects/fetch_006.phpt @@ -0,0 +1,66 @@ +--TEST-- +Lazy objects: magic property fetch may initialize object +--FILE-- +a; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + var_dump($obj->magic); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +int(1) +object(C)#%d (1) { + ["a"]=> + int(1) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +int(1) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["a"]=> + int(1) + } +} diff --git a/Zend/tests/lazy_objects/fetch_007.phpt b/Zend/tests/lazy_objects/fetch_007.phpt new file mode 100644 index 0000000000000..abdb8212a11b2 --- /dev/null +++ b/Zend/tests/lazy_objects/fetch_007.phpt @@ -0,0 +1,70 @@ +--TEST-- +Lazy objects: recursive magic property fetch may initialize object +--FILE-- +$name; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + var_dump($obj->magic); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" + +Warning: Undefined property: C::$magic in %s on line %d +NULL +object(C)#%d (1) { + ["a"]=> + int(1) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" + +Warning: Undefined property: C::$magic in %s on line %d +NULL +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["a"]=> + int(1) + } +} diff --git a/Zend/tests/lazy_objects/fetch_008.phpt b/Zend/tests/lazy_objects/fetch_008.phpt new file mode 100644 index 0000000000000..1a87364e8ded5 --- /dev/null +++ b/Zend/tests/lazy_objects/fetch_008.phpt @@ -0,0 +1,63 @@ +--TEST-- +Lazy objects: property fetch coalesce initializes object +--FILE-- +a ?? null); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +int(1) +object(C)#%d (1) { + ["a"]=> + int(1) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +int(1) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["a"]=> + int(1) + } +} diff --git a/Zend/tests/lazy_objects/fetch_009.phpt b/Zend/tests/lazy_objects/fetch_009.phpt new file mode 100644 index 0000000000000..d4316320c6e9d --- /dev/null +++ b/Zend/tests/lazy_objects/fetch_009.phpt @@ -0,0 +1,63 @@ +--TEST-- +Lazy objects: property fetch coalesce on non existing property initializes object +--FILE-- +unknown ?? null); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +NULL +object(C)#%d (1) { + ["a"]=> + int(1) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +NULL +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["a"]=> + int(1) + } +} diff --git a/Zend/tests/lazy_objects/fetch_010.phpt b/Zend/tests/lazy_objects/fetch_010.phpt new file mode 100644 index 0000000000000..6fb013c3ff1b2 --- /dev/null +++ b/Zend/tests/lazy_objects/fetch_010.phpt @@ -0,0 +1,65 @@ +--TEST-- +Lazy objects: property fetch ref initializes object +--FILE-- +a; + var_dump($ref); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +int(1) +object(C)#%d (1) { + ["a"]=> + &int(1) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +int(1) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["a"]=> + &int(1) + } +} diff --git a/Zend/tests/lazy_objects/fetch_011.phpt b/Zend/tests/lazy_objects/fetch_011.phpt new file mode 100644 index 0000000000000..077a11a2f60ff --- /dev/null +++ b/Zend/tests/lazy_objects/fetch_011.phpt @@ -0,0 +1,62 @@ +--TEST-- +Lazy objects: dynamic property op error +--FILE-- +dynamic++); + } catch(Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + throw new Error("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + throw new Error("initializer"); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +Error: initializer +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +Error: initializer +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} diff --git a/Zend/tests/lazy_objects/fetch_012.phpt b/Zend/tests/lazy_objects/fetch_012.phpt new file mode 100644 index 0000000000000..8c3b591350f80 --- /dev/null +++ b/Zend/tests/lazy_objects/fetch_012.phpt @@ -0,0 +1,62 @@ +--TEST-- +Lazy objects: property op error +--FILE-- +a = 2; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + + try { + var_dump($obj->a++); + } catch (Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + throw new Error("initializer"); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + throw new Error("initializer"); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +Error: initializer +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +Error: initializer +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} diff --git a/Zend/tests/lazy_objects/fetch_013.phpt b/Zend/tests/lazy_objects/fetch_013.phpt new file mode 100644 index 0000000000000..96faaf3f19d10 --- /dev/null +++ b/Zend/tests/lazy_objects/fetch_013.phpt @@ -0,0 +1,93 @@ +--TEST-- +Lazy objects: fetch skipped property does not initialize object +--FILE-- +a = $a; + $this->b = 2; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + $reflector = new ReflectionClass($obj); + $reflector->getProperty('a')->skipLazyInitialization($obj); + $reflector->getProperty('b')->skipLazyInitialization($obj); + $reflector->getProperty('c')->skipLazyInitialization($obj); + + var_dump($obj); + var_dump($obj->a); + var_dump($obj->b); + try { + var_dump($obj->c); + } catch (Error $e) { + printf("%s\n", $e->getMessage()); + } + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(1); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(1); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +object(C)#%d (2) { + ["a"]=> + NULL + ["b"]=> + int(1) + ["c"]=> + uninitialized(int) +} +NULL +int(1) +Typed property C::$c must not be accessed before initialization +object(C)#%d (2) { + ["a"]=> + NULL + ["b"]=> + int(1) + ["c"]=> + uninitialized(int) +} +# Virtual: +object(C)#%d (2) { + ["a"]=> + NULL + ["b"]=> + int(1) + ["c"]=> + uninitialized(int) +} +NULL +int(1) +Typed property C::$c must not be accessed before initialization +object(C)#%d (2) { + ["a"]=> + NULL + ["b"]=> + int(1) + ["c"]=> + uninitialized(int) +} diff --git a/Zend/tests/lazy_objects/fetch_014.phpt b/Zend/tests/lazy_objects/fetch_014.phpt new file mode 100644 index 0000000000000..0320a073039b6 --- /dev/null +++ b/Zend/tests/lazy_objects/fetch_014.phpt @@ -0,0 +1,91 @@ +--TEST-- +Lazy objects: property op on skipped property does not initialize object +--FILE-- +a = 2; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + $reflector = new ReflectionClass($obj); + $reflector->getProperty('a')->skipLazyInitialization($obj); + $reflector->getProperty('b')->skipLazyInitialization($obj); + $reflector->getProperty('c')->skipLazyInitialization($obj); + + var_dump($obj); + var_dump($obj->a++); + var_dump($obj->b++); + try { + var_dump($obj->c++); + } catch (Error $e) { + printf("%s\n", $e->getMessage()); + } + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new c(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +object(C)#%d (2) { + ["a"]=> + NULL + ["b"]=> + int(1) + ["c"]=> + uninitialized(int) +} +NULL +int(1) +Typed property C::$c must not be accessed before initialization +object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + uninitialized(int) +} +# Virtual: +object(C)#%d (2) { + ["a"]=> + NULL + ["b"]=> + int(1) + ["c"]=> + uninitialized(int) +} +NULL +int(1) +Typed property C::$c must not be accessed before initialization +object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + uninitialized(int) +} diff --git a/Zend/tests/lazy_objects/fetch_015.phpt b/Zend/tests/lazy_objects/fetch_015.phpt new file mode 100644 index 0000000000000..c4c77a679329b --- /dev/null +++ b/Zend/tests/lazy_objects/fetch_015.phpt @@ -0,0 +1,87 @@ +--TEST-- +Lazy objects: fetch ref on skipped property does not initialize object +--FILE-- +a; + $ref = &$obj->b; + try { + $ref = &$obj->c; + } catch (Error $e) { + printf("%s\n", $e->getMessage()); + } + var_dump($ref); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) + ["c"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +Cannot access uninitialized non-nullable property C::$c by reference +int(1) +object(C)#%d (2) { + ["a"]=> + NULL + ["b"]=> + &int(1) + ["c"]=> + uninitialized(int) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) + ["c"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +Cannot access uninitialized non-nullable property C::$c by reference +int(1) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["a"]=> + NULL + ["b"]=> + &int(1) + ["c"]=> + uninitialized(int) + } +} diff --git a/Zend/tests/lazy_objects/fetch_016.phpt b/Zend/tests/lazy_objects/fetch_016.phpt new file mode 100644 index 0000000000000..5e27cb77a5abc --- /dev/null +++ b/Zend/tests/lazy_objects/fetch_016.phpt @@ -0,0 +1,75 @@ +--TEST-- +Lazy objects: hooked property fetch may initialize object +--FILE-- +a; } + set($value) { $this->a = $value; } + } + public int $b = 1; + + public function __construct(int $a) { + var_dump(__METHOD__); + $this->a = $a; + $this->b = 2; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + var_dump($obj->a); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(1); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(1); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +int(1) +object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + int(2) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +int(1) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + int(2) + } +} diff --git a/Zend/tests/lazy_objects/fetch_017.phpt b/Zend/tests/lazy_objects/fetch_017.phpt new file mode 100644 index 0000000000000..88d40a59101ac --- /dev/null +++ b/Zend/tests/lazy_objects/fetch_017.phpt @@ -0,0 +1,76 @@ +--TEST-- +Lazy objects: virtual hooked property fetch may initialize object +--FILE-- +_a; } + } + public int $b = 1; + + public function __construct(int $a) { + var_dump(__METHOD__); + $this->_a = $a; + $this->b = 2; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + $a = &$obj->a; + var_dump($a); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(1); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(1); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +int(1) +object(C)#%d (2) { + ["_a"]=> + &int(1) + ["b"]=> + int(2) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +int(1) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["_a"]=> + &int(1) + ["b"]=> + int(2) + } +} diff --git a/Zend/tests/lazy_objects/fetch_018.phpt b/Zend/tests/lazy_objects/fetch_018.phpt new file mode 100644 index 0000000000000..c66d657dfcd0f --- /dev/null +++ b/Zend/tests/lazy_objects/fetch_018.phpt @@ -0,0 +1,62 @@ +--TEST-- +Lazy objects: virtual hooked property fetch may not initialize object +--FILE-- +b = 2; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + var_dump($obj->a); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(1); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(1); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +int(1) +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +int(1) +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} diff --git a/Zend/tests/lazy_objects/gc_001.phpt b/Zend/tests/lazy_objects/gc_001.phpt new file mode 100644 index 0000000000000..db4ab41b8587e --- /dev/null +++ b/Zend/tests/lazy_objects/gc_001.phpt @@ -0,0 +1,54 @@ +--TEST-- +Lazy objects: GC 001 +--FILE-- +newInstanceWithoutConstructor(); + (new ReflectionClass($obj))->resetAsLazyGhost($obj, function () use ($canary) { + }); + + $canary = null; + $obj = null; + + gc_collect_cycles(); +} + +function virtual() { + printf("# Virtual:\n"); + $canary = new Canary(); + + $obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); + (new ReflectionClass($obj))->resetAsLazyProxy($obj, function () use ($canary) { + return new C(); + }); + + $canary = null; + $obj = null; + + gc_collect_cycles(); +} + +ghost(); +virtual(); + +?> +==DONE== +--EXPECT-- +# Ghost: +string(10) "__destruct" +# Virtual: +string(10) "__destruct" +==DONE== diff --git a/Zend/tests/lazy_objects/gc_002.phpt b/Zend/tests/lazy_objects/gc_002.phpt new file mode 100644 index 0000000000000..004907c483adb --- /dev/null +++ b/Zend/tests/lazy_objects/gc_002.phpt @@ -0,0 +1,59 @@ +--TEST-- +Lazy objects: GC 002 +--FILE-- +newInstanceWithoutConstructor(); + (new ReflectionClass($obj))->resetAsLazyGhost($obj, function () use ($canary) { + }); + + $canary->value = $obj; + $canary = null; + $obj = null; + + gc_collect_cycles(); +} + +function virtual() { + printf("# Virtual:\n"); + + $canary = new Canary(); + + $obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); + (new ReflectionClass($obj))->resetAsLazyProxy($obj, function () use ($canary) { + return new C(); + }); + + $canary->value = $obj; + $canary = null; + $obj = null; + + gc_collect_cycles(); +} + +ghost(); +virtual(); + +?> +==DONE== +--EXPECT-- +# Ghost: +string(10) "__destruct" +# Virtual: +string(10) "__destruct" +==DONE== diff --git a/Zend/tests/lazy_objects/gc_003.phpt b/Zend/tests/lazy_objects/gc_003.phpt new file mode 100644 index 0000000000000..a17765a503d7a --- /dev/null +++ b/Zend/tests/lazy_objects/gc_003.phpt @@ -0,0 +1,59 @@ +--TEST-- +Lazy objects: GC 003 +--FILE-- +newInstanceWithoutConstructor(); + (new ReflectionClass($obj))->resetAsLazyGhost($obj, function () use ($canary) { + }); + + $canary->value = $obj; + $obj = null; + $canary = null; + + gc_collect_cycles(); +} + +function virtual() { + printf("# Virtual:\n"); + + $canary = new Canary(); + + $obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); + (new ReflectionClass($obj))->resetAsLazyProxy($obj, function () use ($canary) { + return new C(); + }); + + $canary->value = $obj; + $obj = null; + $canary = null; + + gc_collect_cycles(); +} + +ghost(); +virtual(); + +?> +==DONE== +--EXPECT-- +# Ghost: +string(10) "__destruct" +# Virtual: +string(10) "__destruct" +==DONE== diff --git a/Zend/tests/lazy_objects/gc_004.phpt b/Zend/tests/lazy_objects/gc_004.phpt new file mode 100644 index 0000000000000..f0e64f39de698 --- /dev/null +++ b/Zend/tests/lazy_objects/gc_004.phpt @@ -0,0 +1,67 @@ +--TEST-- +Lazy objects: GC 004 +--FILE-- +newInstanceWithoutConstructor(); + (new ReflectionClass($obj))->resetAsLazyGhost($obj, function () use ($canary) { + }); + + var_dump($obj); // initializes property hash + + $canary->value = $obj; + $obj = null; + $canary = null; + + gc_collect_cycles(); +} + +function virtual() { + printf("# Virtual:\n"); + + $canary = new Canary(); + + $obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); + (new ReflectionClass($obj))->resetAsLazyProxy($obj, function () use ($canary) { + return new C(); + }); + + var_dump($obj); // initializes property hash + + $canary->value = $obj; + $obj = null; + $canary = null; + + gc_collect_cycles(); +} + +ghost(); +virtual(); + +?> +==DONE== +--EXPECTF-- +# Ghost: +object(C)#%d (0) { +} +string(10) "__destruct" +# Virtual: +object(C)#%d (0) { +} +string(10) "__destruct" +==DONE== diff --git a/Zend/tests/lazy_objects/gc_005.phpt b/Zend/tests/lazy_objects/gc_005.phpt new file mode 100644 index 0000000000000..70a20759248bf --- /dev/null +++ b/Zend/tests/lazy_objects/gc_005.phpt @@ -0,0 +1,68 @@ +--TEST-- +Lazy objects: GC 005 +--FILE-- +newInstanceWithoutConstructor(); + $reflector->resetAsLazyGhost($obj, function () use ($canary) { + }); + + $reflector->getProperty('value')->setRawValueWithoutLazyInitialization($obj, $obj); + $reflector = null; + + $canary->value = $obj; + $obj = null; + $canary = null; + + gc_collect_cycles(); +} + +function virtual() { + printf("# Virtual:\n"); + + $canary = new Canary(); + + $reflector = new ReflectionClass(C::class); + $obj = $reflector->newInstanceWithoutConstructor(); + $reflector->resetAsLazyProxy($obj, function () use ($canary) { + return new C(); + }); + + $reflector->getProperty('value')->setRawValueWithoutLazyInitialization($obj, $obj); + $reflector = null; + + $canary->value = $obj; + $obj = null; + $canary = null; + + gc_collect_cycles(); +} + +ghost(); +virtual(); + +?> +==DONE== +--EXPECT-- +# Ghost: +string(10) "__destruct" +# Virtual: +string(10) "__destruct" +==DONE== diff --git a/Zend/tests/lazy_objects/get_initializer.phpt b/Zend/tests/lazy_objects/get_initializer.phpt new file mode 100644 index 0000000000000..30b410be0a6f9 --- /dev/null +++ b/Zend/tests/lazy_objects/get_initializer.phpt @@ -0,0 +1,52 @@ +--TEST-- +Lazy objects: getLazyInitializer() returns initializer +--FILE-- +init(...), +]; + +foreach ($initializers as $i => $initializer) { + $c = $reflector->newLazyGhost($initializer); + if ($reflector->getLazyInitializer($c) !== $initializer) { + printf("Initializer %d: failed\n", $i); + continue; + } + + $reflector->initializeLazyObject($c); + if ($reflector->getLazyInitializer($c) !== null) { + printf("Initializer %d: failed\n", $i); + continue; + } + + printf("Initializer %d: ok\n", $i); +} + +?> +--EXPECT-- +Initializer 0: ok +Initializer 1: ok +Initializer 2: ok +Initializer 3: ok +Initializer 4: ok +Initializer 5: ok +Initializer 6: ok diff --git a/Zend/tests/lazy_objects/ghost_001.phpt b/Zend/tests/lazy_objects/ghost_001.phpt new file mode 100644 index 0000000000000..c7c116e487356 --- /dev/null +++ b/Zend/tests/lazy_objects/ghost_001.phpt @@ -0,0 +1,46 @@ +--TEST-- +Lazy objects: default values are initialized before calling initializer +--FILE-- +a = 3; + $this->b = 4; + } +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + var_dump($obj); + $obj->__construct(); +}); + +var_dump($obj); +var_dump($obj->a); +var_dump($obj); +--EXPECTF-- +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + int(2) +} +string(14) "C::__construct" +int(3) +object(C)#%d (2) { + ["a"]=> + int(3) + ["b"]=> + int(4) +} diff --git a/Zend/tests/lazy_objects/ghost_002.phpt b/Zend/tests/lazy_objects/ghost_002.phpt new file mode 100644 index 0000000000000..8c818c035a841 --- /dev/null +++ b/Zend/tests/lazy_objects/ghost_002.phpt @@ -0,0 +1,45 @@ +--TEST-- +Lazy objects: properties may be left uninitialized by the initializer +--FILE-- +newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +var_dump($obj); +var_dump($obj->a); +try { + var_dump($obj->b); +} catch (Error $e) { + printf("%s\n", $e); +} +var_dump($obj); +--EXPECTF-- +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +NULL +Error: Typed property C::$b must not be accessed before initialization in %s:%d +Stack trace: +#0 {main} +object(C)#%d (1) { + ["a"]=> + NULL + ["b"]=> + uninitialized(int) +} diff --git a/Zend/tests/lazy_objects/init_exception_001.phpt b/Zend/tests/lazy_objects/init_exception_001.phpt new file mode 100644 index 0000000000000..f2e994fc05292 --- /dev/null +++ b/Zend/tests/lazy_objects/init_exception_001.phpt @@ -0,0 +1,51 @@ +--TEST-- +Lazy objects: Object is still lazy after initializer exception +--FILE-- +initializeLazyObject($obj); + } catch (Exception $e) { + printf("%s\n", $e->getMessage()); + } + + printf("Is lazy: %d\n", (new ReflectionClass($obj))->isUninitializedLazyObject($obj)); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 3; + $obj->b = 4; + throw new Exception('initializer exception'); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 3; + $obj->b = 4; + throw new Exception('initializer exception'); +}); + +test('Virtual', $obj); + +--EXPECT-- +# Ghost: +string(11) "initializer" +initializer exception +Is lazy: 1 +# Virtual: +string(11) "initializer" +initializer exception +Is lazy: 1 diff --git a/Zend/tests/lazy_objects/init_exception_002.phpt b/Zend/tests/lazy_objects/init_exception_002.phpt new file mode 100644 index 0000000000000..e14a873b3f9cb --- /dev/null +++ b/Zend/tests/lazy_objects/init_exception_002.phpt @@ -0,0 +1,72 @@ +--TEST-- +Lazy objects: Initializer effects are reverted after exception +--FILE-- +setRawValueWithoutLazyInitialization($obj, 0); + + try { + (new ReflectionClass($obj))->initializeLazyObject($obj); + } catch (Exception $e) { + printf("%s\n", $e->getMessage()); + } + + var_dump($obj); + printf("Is lazy: %d\n", (new ReflectionClass($obj))->isUninitializedLazyObject($obj)); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 3; + $obj->b = 4; + $obj->c = 5; + throw new Exception('initializer exception'); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 3; + $obj->b = 4; + $obj->c = 5; + throw new Exception('initializer exception'); +}); + +// Initializer effects on the virtual proxy are not reverted +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +string(11) "initializer" +initializer exception +lazy ghost object(C)#%d (1) { + ["b"]=> + uninitialized(int) + ["c"]=> + int(0) +} +Is lazy: 1 +# Virtual: +string(11) "initializer" +initializer exception +lazy proxy object(C)#%d (3) { + ["a"]=> + int(3) + ["b"]=> + int(4) + ["c"]=> + int(5) +} +Is lazy: 1 diff --git a/Zend/tests/lazy_objects/init_exception_003.phpt b/Zend/tests/lazy_objects/init_exception_003.phpt new file mode 100644 index 0000000000000..26eabc8bf4204 --- /dev/null +++ b/Zend/tests/lazy_objects/init_exception_003.phpt @@ -0,0 +1,83 @@ +--TEST-- +Lazy objects: Initializer effects are reverted after exception (properties hashtable) +--FILE-- +setRawValueWithoutLazyInitialization($obj, 0); + + // Builds properties hashtable + var_dump(get_mangled_object_vars($obj)); + + try { + (new ReflectionClass($obj))->initializeLazyObject($obj); + } catch (Exception $e) { + printf("%s\n", $e->getMessage()); + } + + var_dump($obj); + printf("Is lazy: %d\n", (new ReflectionClass($obj))->isUninitializedLazyObject($obj)); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 3; + $obj->b = 4; + $obj->c = 5; + throw new Exception('initializer exception'); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 3; + $obj->b = 4; + $obj->c = 5; + throw new Exception('initializer exception'); +}); + +// Initializer effects on the virtual proxy are not reverted +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +array(1) { + ["c"]=> + int(0) +} +string(11) "initializer" +initializer exception +lazy ghost object(C)#%d (1) { + ["b"]=> + uninitialized(int) + ["c"]=> + int(0) +} +Is lazy: 1 +# Virtual: +array(1) { + ["c"]=> + int(0) +} +string(11) "initializer" +initializer exception +lazy proxy object(C)#%d (3) { + ["a"]=> + int(3) + ["b"]=> + int(4) + ["c"]=> + int(5) +} +Is lazy: 1 diff --git a/Zend/tests/lazy_objects/init_exception_005.phpt b/Zend/tests/lazy_objects/init_exception_005.phpt new file mode 100644 index 0000000000000..db5b6dabefb6d --- /dev/null +++ b/Zend/tests/lazy_objects/init_exception_005.phpt @@ -0,0 +1,77 @@ +--TEST-- +Lazy objects: Initializer effects are reverted after exception (dynamic properties) +--FILE-- +setRawValueWithoutLazyInitialization($obj, 0); + + try { + (new ReflectionClass($obj))->initializeLazyObject($obj); + } catch (Exception $e) { + printf("%s\n", $e->getMessage()); + } + + var_dump($obj); + printf("Is lazy: %d\n", (new ReflectionClass($obj))->isUninitializedLazyObject($obj)); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 3; + $obj->b = 4; + $obj->c = 5; + $obj->d = 6; + throw new Exception('initializer exception'); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 3; + $obj->b = 4; + $obj->c = 5; + $obj->d = 6; + throw new Exception('initializer exception'); +}); + +// Initializer effects on the virtual proxy are not reverted +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +string(11) "initializer" +initializer exception +lazy ghost object(C)#%d (1) { + ["b"]=> + uninitialized(int) + ["c"]=> + int(0) +} +Is lazy: 1 +# Virtual: +string(11) "initializer" +initializer exception +lazy proxy object(C)#%d (4) { + ["a"]=> + int(3) + ["b"]=> + int(4) + ["c"]=> + int(5) + ["d"]=> + int(6) +} +Is lazy: 1 diff --git a/Zend/tests/lazy_objects/init_exception_006.phpt b/Zend/tests/lazy_objects/init_exception_006.phpt new file mode 100644 index 0000000000000..28ff9331ceb20 --- /dev/null +++ b/Zend/tests/lazy_objects/init_exception_006.phpt @@ -0,0 +1,84 @@ +--TEST-- +Lazy objects: Initializer effects are reverted after exception (dynamic properties, initialized hashtable) +--FILE-- +setRawValueWithoutLazyInitialization($obj, 0); + + try { + (new ReflectionClass($obj))->initializeLazyObject($obj); + } catch (Exception $e) { + printf("%s\n", $e->getMessage()); + } + + var_dump($obj); + printf("Is lazy: %d\n", (new ReflectionClass($obj))->isUninitializedLazyObject($obj)); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 3; + $obj->b = 4; + $obj->c = 5; + $obj->d = 6; + throw new Exception('initializer exception'); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 3; + $obj->b = 4; + $obj->c = 5; + $obj->d = 6; + throw new Exception('initializer exception'); +}); + +// Initializer effects on the virtual proxy are not reverted +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +array(0) { +} +string(11) "initializer" +initializer exception +lazy ghost object(C)#%d (1) { + ["b"]=> + uninitialized(int) + ["c"]=> + int(0) +} +Is lazy: 1 +# Virtual: +array(0) { +} +string(11) "initializer" +initializer exception +lazy proxy object(C)#%d (4) { + ["a"]=> + int(3) + ["b"]=> + int(4) + ["c"]=> + int(5) + ["d"]=> + int(6) +} +Is lazy: 1 diff --git a/Zend/tests/lazy_objects/init_exception_009.phpt b/Zend/tests/lazy_objects/init_exception_009.phpt new file mode 100644 index 0000000000000..ad6c4232214a6 --- /dev/null +++ b/Zend/tests/lazy_objects/init_exception_009.phpt @@ -0,0 +1,95 @@ +--TEST-- +Lazy objects: Initializer effects are reverted after exception (properties hashtable referenced after initializer) +--FILE-- +setRawValueWithoutLazyInitialization($obj, 0); + + // Builds properties hashtable + var_dump(get_mangled_object_vars($obj)); + + try { + (new ReflectionClass($obj))->initializeLazyObject($obj); + } catch (Exception $e) { + printf("%s\n", $e->getMessage()); + } + + var_dump($obj); + printf("Is lazy: %d\n", (new ReflectionClass($obj))->isUninitializedLazyObject($obj)); + + var_dump($table); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + global $table; + var_dump("initializer"); + $obj->a = 3; + $obj->b = 4; + $obj->c = 5; + $table = (array) $obj; + throw new Exception('initializer exception'); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + global $table; + var_dump("initializer"); + $obj->a = 3; + $obj->b = 4; + $obj->c = 5; + $table = (array) $obj; + throw new Exception('initializer exception'); +}); + +// Initializer effects on the virtual proxy are not reverted +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +array(1) { + ["c"]=> + int(0) +} +string(11) "initializer" +initializer exception +lazy ghost object(C)#%d (1) { + ["b"]=> + uninitialized(int) + ["c"]=> + int(0) +} +Is lazy: 1 + +Warning: Undefined variable $table in %s on line %d +NULL +# Virtual: +array(1) { + ["c"]=> + int(0) +} +string(11) "initializer" +initializer exception +lazy proxy object(C)#%d (3) { + ["a"]=> + int(3) + ["b"]=> + int(4) + ["c"]=> + int(5) +} +Is lazy: 1 + +Warning: Undefined variable $table in %s on line %d +NULL diff --git a/Zend/tests/lazy_objects/init_exception_010.phpt b/Zend/tests/lazy_objects/init_exception_010.phpt new file mode 100644 index 0000000000000..788d92ec6e6b5 --- /dev/null +++ b/Zend/tests/lazy_objects/init_exception_010.phpt @@ -0,0 +1,100 @@ +--TEST-- +Lazy objects: Pre-initialization reference source types are properly handled (no initialization exception) +--FILE-- +a = null; + unset($this->b); + $this->b = null; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + $r = new ReflectionClass($obj); + $r->getProperty('a')->setRawValueWithoutLazyInitialization($obj, null); + $refA = &$obj->a; + $r->getProperty('b')->setRawValueWithoutLazyInitialization($obj, null); + $refB = &$obj->b; + + var_dump($obj); + var_dump($obj->c); + var_dump($obj); + + try { + // $refA retained its reference source type (except for the virtual + // case: its the responsibility of the initializer to propagate + // pre-initialized properties to the instance) + $refA = 1; + } catch (\Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + + // source type was not duplicated + unset($obj->a); + $refA = 1; + + $refB = 1; + +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +$r = (new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(null); +}); + +test('Virtual', $obj); +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (2) { + ["a"]=> + &NULL + ["b"]=> + &NULL +} +string(11) "initializer" +NULL +object(C)#%d (3) { + ["a"]=> + &NULL + ["b"]=> + NULL + ["c"]=> + NULL +} +TypeError: Cannot assign int to reference held by property C::$a of type ?C +# Virtual: +lazy proxy object(C)#%d (2) { + ["a"]=> + &NULL + ["b"]=> + &NULL +} +string(11) "initializer" +NULL +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (3) { + ["a"]=> + NULL + ["b"]=> + NULL + ["c"]=> + NULL + } +} diff --git a/Zend/tests/lazy_objects/init_exception_011.phpt b/Zend/tests/lazy_objects/init_exception_011.phpt new file mode 100644 index 0000000000000..de6c5ff5fd61e --- /dev/null +++ b/Zend/tests/lazy_objects/init_exception_011.phpt @@ -0,0 +1,108 @@ +--TEST-- +Lazy objects: Pre-initialization reference source types are properly handled after initializer exception +--FILE-- +b); + throw new \Exception('initializer exception'); + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + $r = new ReflectionClass($obj); + $r->getProperty('a')->setRawValueWithoutLazyInitialization($obj, null); + $refA = &$obj->a; + $r->getProperty('b')->setRawValueWithoutLazyInitialization($obj, null); + $refB = &$obj->b; + + var_dump($obj); + try { + var_dump($obj->c); + } catch (\Exception $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + var_dump($obj); + + try { + // $refA retained its reference source type (except for the virtual + // case: it is the responsibility of the initializer to propagate + // pre-initialized properties to the instance) + $refA = 1; + } catch (\Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + + // source type was not duplicated + unset($obj->a); + $refA = 1; + + try { + // $refB retained its reference source type + $refB = 1; + } catch (\Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + + // source type was not duplicated + unset($obj->b); + $refB = 1; + +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +$r = (new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(null); +}); + +test('Virtual', $obj); +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (2) { + ["a"]=> + &NULL + ["b"]=> + &NULL +} +string(11) "initializer" +Exception: initializer exception +lazy ghost object(C)#%d (2) { + ["a"]=> + &NULL + ["b"]=> + &NULL +} +TypeError: Cannot assign int to reference held by property C::$a of type ?C +TypeError: Cannot assign int to reference held by property C::$b of type ?C +# Virtual: +lazy proxy object(C)#%d (2) { + ["a"]=> + &NULL + ["b"]=> + &NULL +} +string(11) "initializer" +Exception: initializer exception +lazy proxy object(C)#%d (2) { + ["a"]=> + &NULL + ["b"]=> + &NULL +} +TypeError: Cannot assign int to reference held by property C::$a of type ?C +TypeError: Cannot assign int to reference held by property C::$b of type ?C diff --git a/Zend/tests/lazy_objects/init_exception_012.phpt b/Zend/tests/lazy_objects/init_exception_012.phpt new file mode 100644 index 0000000000000..245cfa64e0470 --- /dev/null +++ b/Zend/tests/lazy_objects/init_exception_012.phpt @@ -0,0 +1,59 @@ +--TEST-- +Lazy objects: Object is still lazy after initializer exception (overridden prop) +--FILE-- +getProperty('b')->skipLazyInitialization($obj); + $i = 5; + $obj->b = &$i; + + try { + $reflector->initializeLazyObject($obj); + } catch (Exception $e) { + printf("%s\n", $e->getMessage()); + } + + printf("Is lazy: %d\n", (new ReflectionClass($obj))->isUninitializedLazyObject($obj)); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 3; + $obj->b = 4; + throw new Exception('initializer exception'); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 3; + $obj->b = 4; + throw new Exception('initializer exception'); +}); + +test('Virtual', $obj); + +--EXPECT-- +# Ghost: +string(11) "initializer" +initializer exception +Is lazy: 1 +# Virtual: +string(11) "initializer" +initializer exception +Is lazy: 1 diff --git a/Zend/tests/lazy_objects/initialize_001.phpt b/Zend/tests/lazy_objects/initialize_001.phpt new file mode 100644 index 0000000000000..5f1966974af3e --- /dev/null +++ b/Zend/tests/lazy_objects/initialize_001.phpt @@ -0,0 +1,62 @@ +--TEST-- +Lazy objects: ReflectionClass::initializeLazyObject() +--FILE-- +isUninitializedLazyObject($obj)); + + var_dump($reflector?->initializeLazyObject($obj)); + + printf("Initialized:\n"); + var_dump(!$reflector->isUninitializedLazyObject($obj)); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 1; +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + $c = new C(); + $c->a = 1; + return $c; +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +Initialized: +bool(false) +string(11) "initializer" +object(C)#%d (1) { + ["a"]=> + int(1) +} +Initialized: +bool(true) +# Virtual: +Initialized: +bool(false) +string(11) "initializer" +object(C)#%d (1) { + ["a"]=> + int(1) +} +Initialized: +bool(true) diff --git a/Zend/tests/lazy_objects/initialize_002.phpt b/Zend/tests/lazy_objects/initialize_002.phpt new file mode 100644 index 0000000000000..867b2d54b53d9 --- /dev/null +++ b/Zend/tests/lazy_objects/initialize_002.phpt @@ -0,0 +1,60 @@ +--TEST-- +Lazy objects: ReflectionClass::initializeLazyObject() on an initialized object is a no-op +--FILE-- +a); + + var_dump(!$reflector->isUninitializedLazyObject($obj)); + + var_dump($reflector?->initializeLazyObject($obj)); + + var_dump(!$reflector->isUninitializedLazyObject($obj)); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 1; +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + $c = new C(); + $c->a = 1; + return $c; +}); + +test('Virtual', $obj); + +--EXPECT-- +# Ghost: +string(11) "initializer" +int(1) +bool(true) +object(C)#2 (1) { + ["a"]=> + int(1) +} +bool(true) +# Virtual: +string(11) "initializer" +int(1) +bool(true) +object(C)#4 (1) { + ["a"]=> + int(1) +} +bool(true) diff --git a/Zend/tests/lazy_objects/initialize_005.phpt b/Zend/tests/lazy_objects/initialize_005.phpt new file mode 100644 index 0000000000000..a2449aec79125 --- /dev/null +++ b/Zend/tests/lazy_objects/initialize_005.phpt @@ -0,0 +1,51 @@ +--TEST-- +Lazy objects: ReflectionClass::initializeLazyObject() error +--FILE-- +isUninitializedLazyObject($obj)); + + try { + var_dump($reflector?->initializeLazyObject($obj)); + } catch (Exception $e) { + printf("%s\n", $e->getMessage()); + } + + var_dump(!$reflector->isUninitializedLazyObject($obj)); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + throw new \Exception('initializer exception'); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + throw new \Exception('initializer exception'); +}); + +test('Virtual', $obj); + +--EXPECT-- +# Ghost: +bool(false) +string(11) "initializer" +initializer exception +bool(false) +# Virtual: +bool(false) +string(11) "initializer" +initializer exception +bool(false) diff --git a/Zend/tests/lazy_objects/is_initialized_001.phpt b/Zend/tests/lazy_objects/is_initialized_001.phpt new file mode 100644 index 0000000000000..d121417a889db --- /dev/null +++ b/Zend/tests/lazy_objects/is_initialized_001.phpt @@ -0,0 +1,26 @@ +--TEST-- +Lazy objects: ReflectionClass::isInitialized +--FILE-- +newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 1; +}); + +$reflector = new ReflectionClass($obj); +var_dump(!$reflector->isUninitializedLazyObject($obj)); + +var_dump($obj->a); + +var_dump(!$reflector->isUninitializedLazyObject($obj)); +--EXPECTF-- +bool(false) +string(11) "initializer" +int(1) +bool(true) diff --git a/Zend/tests/lazy_objects/is_uninitialized_lazy_object.phpt b/Zend/tests/lazy_objects/is_uninitialized_lazy_object.phpt new file mode 100644 index 0000000000000..62fd7c1c70542 --- /dev/null +++ b/Zend/tests/lazy_objects/is_uninitialized_lazy_object.phpt @@ -0,0 +1,31 @@ +--TEST-- +Lazy objects: isUninitializedLazyObject() +--FILE-- +a = 1; + } +} + +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function () {}); +var_dump($reflector->isUninitializedLazyObject($obj)); +$reflector->initializeLazyObject($obj); +var_dump($reflector->isUninitializedLazyObject($obj)); + +$obj = $reflector->newLazyProxy(function () { return new C(); }); +var_dump($reflector->isUninitializedLazyObject($obj)); +$reflector->initializeLazyObject($obj); +var_dump($reflector->isUninitializedLazyObject($obj)); + +?> +--EXPECT-- +bool(true) +bool(false) +bool(true) +bool(false) diff --git a/Zend/tests/lazy_objects/isset_001.phpt b/Zend/tests/lazy_objects/isset_001.phpt new file mode 100644 index 0000000000000..3f9c918c9ebfc --- /dev/null +++ b/Zend/tests/lazy_objects/isset_001.phpt @@ -0,0 +1,72 @@ +--TEST-- +Lazy objects: property isset initializes object +--FILE-- +a = $a; + $this->b = 2; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + var_dump(isset($obj->a)); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(1); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(1); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +bool(true) +object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + int(2) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +bool(true) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + int(2) + } +} diff --git a/Zend/tests/lazy_objects/isset_002.phpt b/Zend/tests/lazy_objects/isset_002.phpt new file mode 100644 index 0000000000000..39722791e5687 --- /dev/null +++ b/Zend/tests/lazy_objects/isset_002.phpt @@ -0,0 +1,75 @@ +--TEST-- +Lazy objects: hooked property isset may initialize object +--FILE-- +a; } + set($value) { $this->a = $value; } + } + public int $b = 1; + + public function __construct(int $a) { + var_dump(__METHOD__); + $this->a = $a; + $this->b = 2; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + var_dump(isset($obj->a)); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(1); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(1); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +bool(true) +object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + int(2) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +bool(true) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + int(2) + } +} diff --git a/Zend/tests/lazy_objects/isset_003.phpt b/Zend/tests/lazy_objects/isset_003.phpt new file mode 100644 index 0000000000000..9ade21d693e1e --- /dev/null +++ b/Zend/tests/lazy_objects/isset_003.phpt @@ -0,0 +1,64 @@ +--TEST-- +Lazy objects: hooked property isset may not initialize object +--FILE-- +a = $a; + $this->b = 2; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + var_dump(isset($obj->a)); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(1); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(1); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +bool(true) +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +bool(true) +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} diff --git a/Zend/tests/lazy_objects/make_lazy_already_exception.phpt b/Zend/tests/lazy_objects/make_lazy_already_exception.phpt new file mode 100644 index 0000000000000..5dc8fb675d550 --- /dev/null +++ b/Zend/tests/lazy_objects/make_lazy_already_exception.phpt @@ -0,0 +1,55 @@ +--TEST-- +Lazy objects: makeLazy() on already lazy object is not allowed +--FILE-- +resetAsLazyGhost($obj, function () {}); + +try { + $r->resetAsLazyGhost($obj, function ($obj) { + }); +} catch (\Exception $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +printf("# Virtual:\n"); + +$obj = new C(); +$r->resetAsLazyProxy($obj, function () {}); + +try { + $r->resetAsLazyProxy($obj, function ($obj) { + }); +} catch (\Exception $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +$obj = new C(); +$r->resetAsLazyProxy($obj, function () { + return new C(); +}); +$r->initializeLazyObject($obj); + +try { + $r->resetAsLazyProxy($obj, function ($obj) { + }); +} catch (\Exception $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +?> +==DONE== +--EXPECT-- +# Ghost: +ReflectionException: Object is already lazy +# Virtual: +ReflectionException: Object is already lazy +==DONE== diff --git a/Zend/tests/lazy_objects/make_lazy_destructor_001.phpt b/Zend/tests/lazy_objects/make_lazy_destructor_001.phpt new file mode 100644 index 0000000000000..e5400d7f51126 --- /dev/null +++ b/Zend/tests/lazy_objects/make_lazy_destructor_001.phpt @@ -0,0 +1,59 @@ +--TEST-- +Lazy objects: makeLazy calls destructor of pre-existing object +--FILE-- +a = 1; + } + + public function __destruct() { + var_dump(__METHOD__); + } +} + +print "# Ghost:\n"; + +$obj = new C(); +print "In makeLazy\n"; +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); +print "After makeLazy\n"; + +var_dump($obj->a); +$obj = null; + +print "# Virtual:\n"; + +$obj = new C(); +print "In makeLazy\n"; +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); +print "After makeLazy\n"; + +var_dump($obj->a); +$obj = null; + +?> +--EXPECT-- +# Ghost: +In makeLazy +string(13) "C::__destruct" +After makeLazy +string(11) "initializer" +int(1) +string(13) "C::__destruct" +# Virtual: +In makeLazy +string(13) "C::__destruct" +After makeLazy +string(11) "initializer" +int(1) +string(13) "C::__destruct" diff --git a/Zend/tests/lazy_objects/make_lazy_destructor_002.phpt b/Zend/tests/lazy_objects/make_lazy_destructor_002.phpt new file mode 100644 index 0000000000000..bc964d5ea2925 --- /dev/null +++ b/Zend/tests/lazy_objects/make_lazy_destructor_002.phpt @@ -0,0 +1,57 @@ +--TEST-- +Lazy objects: makeLazy calls destructor of pre-existing object, unless SKIP_DESTRUCTOR flag is used +--FILE-- +a = 1; + } + + public function __destruct() { + var_dump(__METHOD__); + } +} + +print "# Ghost:\n"; + +$obj = new C(); +print "In makeLazy\n"; +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}, ReflectionClass::SKIP_DESTRUCTOR); +print "After makeLazy\n"; + +var_dump($obj->a); +$obj = null; + +print "# Virtual:\n"; + +$obj = new C(); +print "In makeLazy\n"; +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}, ReflectionClass::SKIP_DESTRUCTOR); +print "After makeLazy\n"; + +var_dump($obj->a); +$obj = null; + +?> +--EXPECT-- +# Ghost: +In makeLazy +After makeLazy +string(11) "initializer" +int(1) +string(13) "C::__destruct" +# Virtual: +In makeLazy +After makeLazy +string(11) "initializer" +int(1) +string(13) "C::__destruct" diff --git a/Zend/tests/lazy_objects/make_lazy_destructor_003.phpt b/Zend/tests/lazy_objects/make_lazy_destructor_003.phpt new file mode 100644 index 0000000000000..4a0653ba327ec --- /dev/null +++ b/Zend/tests/lazy_objects/make_lazy_destructor_003.phpt @@ -0,0 +1,55 @@ +--TEST-- +Lazy objects: Destructor exception in makeLazy +--FILE-- +a = 1; + } + + public function __destruct() { + throw new \Exception(__METHOD__); + } +} + +print "# Ghost:\n"; + +$obj = new C(); +try { + (new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); + }); +} catch (\Exception $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +// Object was not made lazy +var_dump(!(new ReflectionClass($obj))->isUninitializedLazyObject($obj)); + +print "# Virtual:\n"; + +$obj = new C(); +try { + (new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); + }); +} catch (\Exception $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +// Object was not made lazy +var_dump(!(new ReflectionClass($obj))->isUninitializedLazyObject($obj)); + +?> +--EXPECT-- +# Ghost: +Exception: C::__destruct +bool(true) +# Virtual: +Exception: C::__destruct +bool(true) diff --git a/Zend/tests/lazy_objects/mark_as_initialized_001.phpt b/Zend/tests/lazy_objects/mark_as_initialized_001.phpt new file mode 100644 index 0000000000000..b31852b49ff35 --- /dev/null +++ b/Zend/tests/lazy_objects/mark_as_initialized_001.phpt @@ -0,0 +1,66 @@ +--TEST-- +Lazy objects: markLazyObjectAsInitialized() initializes properties to their default value and skips initializer +--FILE-- +isUninitializedLazyObject($obj)); + + printf("markLazyObjectAsInitialized(true) returns \$obj:\n"); + var_dump($reflector?->markLazyObjectAsInitialized($obj) === $obj); + + printf("Initialized:\n"); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 1; +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + $c = new C(); + $c->a = 1; + return $c; +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +Initialized: +bool(false) +markLazyObjectAsInitialized(true) returns $obj: +bool(true) +Initialized: +bool(true) +object(C)#%d (1) { + ["a"]=> + int(1) +} +# Virtual: +Initialized: +bool(false) +markLazyObjectAsInitialized(true) returns $obj: +bool(true) +Initialized: +bool(true) +object(C)#%d (1) { + ["a"]=> + int(1) +} diff --git a/Zend/tests/lazy_objects/new_instance_lazy_001.phpt b/Zend/tests/lazy_objects/new_instance_lazy_001.phpt new file mode 100644 index 0000000000000..32c2e1680c65c --- /dev/null +++ b/Zend/tests/lazy_objects/new_instance_lazy_001.phpt @@ -0,0 +1,20 @@ +--TEST-- +Lazy objects: newInstanceLazy can not instantiate internal classes +--FILE-- +newInstanceWithoutConstructor(); + +foreach (['resetAsLazyGhost', 'resetAsLazyProxy'] as $strategy) { + try { + $reflector->$strategy($obj, function ($obj) { + var_dump("initializer"); + }); + } catch (Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } +} +--EXPECT-- +Error: Cannot make instance of internal class lazy: ReflectionClass is internal +Error: Cannot make instance of internal class lazy: ReflectionClass is internal diff --git a/Zend/tests/lazy_objects/new_instance_lazy_002.phpt b/Zend/tests/lazy_objects/new_instance_lazy_002.phpt new file mode 100644 index 0000000000000..c8f3463c94edc --- /dev/null +++ b/Zend/tests/lazy_objects/new_instance_lazy_002.phpt @@ -0,0 +1,21 @@ +--TEST-- +Lazy objects: newInstanceLazy can not instantiate sub-class of internal classes +--FILE-- +newInstanceWithoutConstructor(); + try { + $reflector->$strategy($obj, function ($obj) { + var_dump("initializer"); + }); + } catch (Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } +} +--EXPECT-- +Error: Cannot make instance of internal class lazy: C inherits internal class ReflectionClass +Error: Cannot make instance of internal class lazy: C inherits internal class ReflectionClass diff --git a/Zend/tests/lazy_objects/new_instance_lazy_003.phpt b/Zend/tests/lazy_objects/new_instance_lazy_003.phpt new file mode 100644 index 0000000000000..00516a19b737f --- /dev/null +++ b/Zend/tests/lazy_objects/new_instance_lazy_003.phpt @@ -0,0 +1,22 @@ +--TEST-- +Lazy objects: newInstanceLazy can instantiate sub-class of user classes +--FILE-- +newInstanceWithoutConstructor(); + $reflector->$strategy($obj, function ($obj) { + var_dump("initializer"); + }); + var_dump($obj); +} + +--EXPECTF-- +object(C)#%d (0) { +} +object(C)#%d (0) { +} diff --git a/Zend/tests/lazy_objects/new_instance_lazy_004.phpt b/Zend/tests/lazy_objects/new_instance_lazy_004.phpt new file mode 100644 index 0000000000000..c4782b46b943d --- /dev/null +++ b/Zend/tests/lazy_objects/new_instance_lazy_004.phpt @@ -0,0 +1,18 @@ +--TEST-- +Lazy objects: newInstanceLazy can instantiate stdClass +--FILE-- +newInstanceWithoutConstructor(); + $reflector->$strategy($obj, function ($obj) { + var_dump("initializer"); + }); + var_dump($obj); +} +--EXPECTF-- +object(stdClass)#%d (0) { +} +object(stdClass)#%d (0) { +} diff --git a/Zend/tests/lazy_objects/new_instance_lazy_005.phpt b/Zend/tests/lazy_objects/new_instance_lazy_005.phpt new file mode 100644 index 0000000000000..fb028149c021b --- /dev/null +++ b/Zend/tests/lazy_objects/new_instance_lazy_005.phpt @@ -0,0 +1,21 @@ +--TEST-- +Lazy objects: newInstanceLazy can instantiate sub-class of stdClass +--FILE-- +newInstanceWithoutConstructor(); + $reflector->$strategy($obj, function ($obj) { + var_dump("initializer"); + }); + var_dump($obj); +} + +--EXPECTF-- +object(C)#%d (0) { +} +object(C)#%d (0) { +} diff --git a/Zend/tests/lazy_objects/object_with_ast_const_001.phpt b/Zend/tests/lazy_objects/object_with_ast_const_001.phpt new file mode 100644 index 0000000000000..018c46e4915e5 --- /dev/null +++ b/Zend/tests/lazy_objects/object_with_ast_const_001.phpt @@ -0,0 +1,27 @@ +--TEST-- +Lazy objects: Class constants are updated before initialization +--FILE-- +newLazyGhost(function () { }); + +function f() { + define('FOO', new stdClass); +} + +f(); + +try { + var_dump($c->a); +} catch (\Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +--EXPECTF-- +object(stdClass)#%d (0) { +} diff --git a/Zend/tests/lazy_objects/object_with_ast_const_002.phpt b/Zend/tests/lazy_objects/object_with_ast_const_002.phpt new file mode 100644 index 0000000000000..d3f1ca0f35f5c --- /dev/null +++ b/Zend/tests/lazy_objects/object_with_ast_const_002.phpt @@ -0,0 +1,26 @@ +--TEST-- +Lazy objects: Class constants are updated before initialization: update constant failure +--FILE-- +newLazyGhost(function () { }); + +function f() { + define('FOO', new stdClass); +} + +f(); + +try { + var_dump($c->a); +} catch (\Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +--EXPECT-- +TypeError: Cannot assign stdClass to property C::$a of type C diff --git a/Zend/tests/lazy_objects/props_of_proxy_must_not_be_lazy_004.phpt b/Zend/tests/lazy_objects/props_of_proxy_must_not_be_lazy_004.phpt new file mode 100644 index 0000000000000..3858f3ff4216c --- /dev/null +++ b/Zend/tests/lazy_objects/props_of_proxy_must_not_be_lazy_004.phpt @@ -0,0 +1,90 @@ +--TEST-- +Lazy objects: Object is not lazy anymore if all props have been assigned a value (overridden prop) +--FILE-- +b = 'b'; + } +} + +class C extends B { + public string $a; + public readonly string $b; + + public function __construct() { + parent::__construct(); + $this->a = 'a'; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + $reflector = new ReflectionClass($obj); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, 'a1'); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + + // Should not count a second prop initialization + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, 'a2'); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + + try { + // Should not count a prop initialization + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, new stdClass); + } catch (Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + + (new ReflectionProperty(B::class, 'b'))->setRawValueWithoutLazyInitialization($obj, 'b'); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +bool(false) +bool(false) +bool(false) +TypeError: Cannot assign stdClass to property C::$a of type string +bool(true) +object(C)#%d (2) { + ["b"]=> + string(1) "b" + ["a"]=> + string(2) "a2" +} +# Virtual: +bool(false) +bool(false) +bool(false) +TypeError: Cannot assign stdClass to property C::$a of type string +bool(true) +object(C)#%d (2) { + ["b"]=> + string(1) "b" + ["a"]=> + string(2) "a2" +} diff --git a/Zend/tests/lazy_objects/realize_001.phpt b/Zend/tests/lazy_objects/realize_001.phpt new file mode 100644 index 0000000000000..69d78cdbe1f8f --- /dev/null +++ b/Zend/tests/lazy_objects/realize_001.phpt @@ -0,0 +1,95 @@ +--TEST-- +Lazy objects: Object is not lazy anymore if all props have been assigned a value +--FILE-- +b = 'b'; + } +} + +#[AllowDynamicProperties] +class C extends B { + public string $a; + + public function __construct() { + parent::__construct(); + $this->a = 'a'; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + $reflector = new ReflectionClass($obj); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, 'a1'); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + + // Should not count a second prop initialization + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, 'a2'); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + + try { + // Should not count a prop initialization + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, new stdClass); + } catch (Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + + // Should not count a prop initialization + //$reflector->getProperty('b')->setRawValueWithoutLazyInitialization($obj, 'dynamic B'); + //var_dump(!$reflector->isUninitializedLazyObject($obj)); + + (new ReflectionProperty(B::class, 'b'))->setRawValueWithoutLazyInitialization($obj, 'b'); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +bool(false) +bool(false) +bool(false) +TypeError: Cannot assign stdClass to property C::$a of type string +bool(true) +object(C)#%d (2) { + ["b":"B":private]=> + string(1) "b" + ["a"]=> + string(2) "a2" +} +# Virtual: +bool(false) +bool(false) +bool(false) +TypeError: Cannot assign stdClass to property C::$a of type string +bool(true) +object(C)#%d (2) { + ["b":"B":private]=> + string(1) "b" + ["a"]=> + string(2) "a2" +} diff --git a/Zend/tests/lazy_objects/realize_002.phpt b/Zend/tests/lazy_objects/realize_002.phpt new file mode 100644 index 0000000000000..6451b5e0127de --- /dev/null +++ b/Zend/tests/lazy_objects/realize_002.phpt @@ -0,0 +1,100 @@ +--TEST-- +Lazy objects: Object is not lazy anymore if all props have been skipped +--FILE-- +b = 'b'; + } +} + +#[AllowDynamicProperties] +class C extends B { + public string $a; + + public function __construct() { + parent::__construct(); + $this->a = 'a'; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + $reflector = new ReflectionClass($obj); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + + $reflector->getProperty('a')->skipLazyInitialization($obj); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + + // Should not count a second prop initialization + $reflector->getProperty('a')->skipLazyInitialization($obj); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + + try { + // Should not count a prop initialization + $reflector->getProperty('xxx')->skipLazyInitialization($obj); + } catch (ReflectionException $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + + try { + // Should not count a prop initialization + $reflector->getProperty('b')->skipLazyInitialization($obj); + } catch (ReflectionException $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + + (new ReflectionProperty(B::class, 'b'))->skipLazyInitialization($obj); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +bool(false) +bool(false) +bool(false) +ReflectionException: Property C::$xxx does not exist +ReflectionException: Property C::$b does not exist +bool(true) +object(C)#%d (0) { + ["b":"B":private]=> + uninitialized(string) + ["a"]=> + uninitialized(string) +} +# Virtual: +bool(false) +bool(false) +bool(false) +ReflectionException: Property C::$xxx does not exist +ReflectionException: Property C::$b does not exist +bool(true) +object(C)#%d (0) { + ["b":"B":private]=> + uninitialized(string) + ["a"]=> + uninitialized(string) +} diff --git a/Zend/tests/lazy_objects/realize_003.phpt b/Zend/tests/lazy_objects/realize_003.phpt new file mode 100644 index 0000000000000..5450eda1aeba1 --- /dev/null +++ b/Zend/tests/lazy_objects/realize_003.phpt @@ -0,0 +1,78 @@ +--TEST-- +Lazy objects: Object with no props is never lazy +--FILE-- +isUninitializedLazyObject($obj)); + var_dump($obj); + + var_dump((new ReflectionClass($obj2::class))->isUninitializedLazyObject($obj2)); + var_dump($obj2); + + var_dump((new ReflectionClass($obj3::class))->isUninitializedLazyObject($obj3)); + var_dump($obj3); +} + +$obj = new C(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); +}); + +$obj2 = new D(); +$obj2->dynamic = 'value'; +(new ReflectionClass($obj2))->resetAsLazyGhost($obj2, function ($obj2) { + var_dump("initializer"); +}); + +$obj3 = (new ReflectionClass(C::class))->newLazyGhost(function () { + var_dump("initializer"); +}); + +test('Ghost', $obj, $obj2, $obj3); + +$obj = new C(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); +}); + +$obj2 = new D(); +$obj2->dynamic = 'value'; +(new ReflectionClass($obj2))->resetAsLazyProxy($obj2, function ($obj2) { + var_dump("initializer"); +}); + +$obj3 = (new ReflectionClass(C::class))->newLazyGhost(function () { + var_dump("initializer"); +}); + +test('Virtual', $obj, $obj2, $obj3); + +--EXPECTF-- +# Ghost: +bool(false) +object(C)#%d (0) { +} +bool(false) +object(D)#%d (0) { +} +bool(false) +object(C)#%d (0) { +} +# Virtual: +bool(false) +object(C)#%d (0) { +} +bool(false) +object(D)#%d (0) { +} +bool(false) +object(C)#%d (0) { +} diff --git a/Zend/tests/lazy_objects/reflection_lazy_object_skip_property_001.phpt b/Zend/tests/lazy_objects/reflection_lazy_object_skip_property_001.phpt new file mode 100644 index 0000000000000..ea4cfda907646 --- /dev/null +++ b/Zend/tests/lazy_objects/reflection_lazy_object_skip_property_001.phpt @@ -0,0 +1,349 @@ +--TEST-- +Lazy objects: ReflectionClass::skipInitializerForProperty() prevent properties from triggering initializer +--FILE-- +hooked; } + set ($value) { $this->hooked = strtoupper($value); } + } + + public $virtual { + get { return 'virtual'; } + set ($value) { } + } +} + +class B extends A { + private $priv = 'privB'; + public $pubB = 'pubB'; + + private readonly string $readonly; +} + +set_error_handler(function ($errno, $errstr) { + throw new Error($errstr); +}); + +function testProperty(callable $makeObj, $propReflector) { + + $reflector = new ReflectionClass(B::class); + + $getValue = function ($obj, $propReflector) { + $name = $propReflector->getName(); + return $obj->$name; + }; + + printf("\n## %s", $propReflector); + + printf("\nskipInitializerForProperty():\n"); + $obj = $makeObj(); + $skept = false; + try { + $propReflector->skipLazyInitialization($obj); + $skept = true; + } catch (ReflectionException $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + if (!$reflector->isUninitializedLazyObject($obj)) { + printf("Object was unexpectedly initialized (1)\n"); + } + if ($skept) { + try { + printf("getValue(): "); + var_dump($getValue($obj, $propReflector)); + } catch (\Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + if (!$propReflector->isStatic()) { + $propReflector->setValue($obj, ''); + } + if (!$reflector->isUninitializedLazyObject($obj)) { + printf("Object was unexpectedly initialized (1)\n"); + } + } + + printf("\nsetRawValueWithoutLazyInitialization():\n"); + $obj = $makeObj(); + $skept = false; + try { + $propReflector->setRawValueWithoutLazyInitialization($obj, 'value'); + $skept = true; + } catch (ReflectionException $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + if (!$reflector->isUninitializedLazyObject($obj)) { + printf("Object was unexpectedly initialized (1)\n"); + } + if ($skept) { + try { + printf("getValue(): "); + var_dump($getValue($obj, $propReflector)); + } catch (\Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + if (!$reflector->isUninitializedLazyObject($obj)) { + printf("Object was unexpectedly initialized (1)\n"); + } + } +} + +function test(string $name, callable $makeObj) { + printf("# %s:\n", $name); + + $reflector = new ReflectionClass(B::class); + + foreach ($reflector->getProperties() as $propReflector) { + testProperty($makeObj, $propReflector); + } + + testProperty($makeObj, new class { + function getName() { + return 'dynamicProp'; + } + function setValue($obj, $value) { + $obj->dynamicProp = $value; + } + function isStatic() { + return false; + } + // TODO: refactor this test + function skipLazyInitialization(object $object) { + throw new \ReflectionException(); + } + function setRawValueWithoutLazyInitialization(object $object) { + throw new \ReflectionException(); + } + function __toString() { + return "Property [ \$dynamicProp ]\n"; + } + }); +} + +$reflector = new ReflectionClass(B::class); + +$factory = function () use ($reflector) { + return $reflector->newLazyGhost(function ($obj) { + throw new \Exception('initializer'); + }); +}; + +test('Ghost', $factory); + +$factory = function () use ($reflector) { + return $reflector->newLazyGhost(function ($obj) { + throw new \Exception('initializer'); + }); +}; + +test('Virtual', $factory); + +?> +--EXPECT-- +# Ghost: + +## Property [ private $priv = 'privB' ] + +skipInitializerForProperty(): +getValue(): Error: Cannot access private property B::$priv + +setRawValueWithoutLazyInitialization(): +getValue(): Error: Cannot access private property B::$priv + +## Property [ public $pubB = 'pubB' ] + +skipInitializerForProperty(): +getValue(): string(4) "pubB" + +setRawValueWithoutLazyInitialization(): +getValue(): string(5) "value" + +## Property [ private readonly string $readonly ] + +skipInitializerForProperty(): +getValue(): Error: Cannot access private property B::$readonly + +setRawValueWithoutLazyInitialization(): +getValue(): Error: Cannot access private property B::$readonly + +## Property [ protected $prot = 'prot' ] + +skipInitializerForProperty(): +getValue(): Error: Cannot access protected property B::$prot + +setRawValueWithoutLazyInitialization(): +getValue(): Error: Cannot access protected property B::$prot + +## Property [ public $pubA = 'pubA' ] + +skipInitializerForProperty(): +getValue(): string(4) "pubA" + +setRawValueWithoutLazyInitialization(): +getValue(): string(5) "value" + +## Property [ public static $static = 'static' ] + +skipInitializerForProperty(): +ReflectionException: Can not use skipLazyInitialization on static property B::$static + +setRawValueWithoutLazyInitialization(): +ReflectionException: Can not use setRawValueWithoutLazyInitialization on static property B::$static + +## Property [ public $noDefault = NULL ] + +skipInitializerForProperty(): +getValue(): NULL + +setRawValueWithoutLazyInitialization(): +getValue(): string(5) "value" + +## Property [ public string $noDefaultTyped ] + +skipInitializerForProperty(): +getValue(): Error: Typed property A::$noDefaultTyped must not be accessed before initialization + +setRawValueWithoutLazyInitialization(): +getValue(): string(5) "value" + +## Property [ public $initialized = NULL ] + +skipInitializerForProperty(): +getValue(): NULL + +setRawValueWithoutLazyInitialization(): +getValue(): string(5) "value" + +## Property [ public $hooked = NULL ] + +skipInitializerForProperty(): +getValue(): NULL + +setRawValueWithoutLazyInitialization(): +getValue(): string(5) "value" + +## Property [ public $virtual ] + +skipInitializerForProperty(): +ReflectionException: Can not use skipLazyInitialization on virtual property B::$virtual + +setRawValueWithoutLazyInitialization(): +ReflectionException: Can not use setRawValueWithoutLazyInitialization on virtual property B::$virtual + +## Property [ $dynamicProp ] + +skipInitializerForProperty(): +ReflectionException: + +setRawValueWithoutLazyInitialization(): +ReflectionException: +# Virtual: + +## Property [ private $priv = 'privB' ] + +skipInitializerForProperty(): +getValue(): Error: Cannot access private property B::$priv + +setRawValueWithoutLazyInitialization(): +getValue(): Error: Cannot access private property B::$priv + +## Property [ public $pubB = 'pubB' ] + +skipInitializerForProperty(): +getValue(): string(4) "pubB" + +setRawValueWithoutLazyInitialization(): +getValue(): string(5) "value" + +## Property [ private readonly string $readonly ] + +skipInitializerForProperty(): +getValue(): Error: Cannot access private property B::$readonly + +setRawValueWithoutLazyInitialization(): +getValue(): Error: Cannot access private property B::$readonly + +## Property [ protected $prot = 'prot' ] + +skipInitializerForProperty(): +getValue(): Error: Cannot access protected property B::$prot + +setRawValueWithoutLazyInitialization(): +getValue(): Error: Cannot access protected property B::$prot + +## Property [ public $pubA = 'pubA' ] + +skipInitializerForProperty(): +getValue(): string(4) "pubA" + +setRawValueWithoutLazyInitialization(): +getValue(): string(5) "value" + +## Property [ public static $static = 'static' ] + +skipInitializerForProperty(): +ReflectionException: Can not use skipLazyInitialization on static property B::$static + +setRawValueWithoutLazyInitialization(): +ReflectionException: Can not use setRawValueWithoutLazyInitialization on static property B::$static + +## Property [ public $noDefault = NULL ] + +skipInitializerForProperty(): +getValue(): NULL + +setRawValueWithoutLazyInitialization(): +getValue(): string(5) "value" + +## Property [ public string $noDefaultTyped ] + +skipInitializerForProperty(): +getValue(): Error: Typed property A::$noDefaultTyped must not be accessed before initialization + +setRawValueWithoutLazyInitialization(): +getValue(): string(5) "value" + +## Property [ public $initialized = NULL ] + +skipInitializerForProperty(): +getValue(): NULL + +setRawValueWithoutLazyInitialization(): +getValue(): string(5) "value" + +## Property [ public $hooked = NULL ] + +skipInitializerForProperty(): +getValue(): NULL + +setRawValueWithoutLazyInitialization(): +getValue(): string(5) "value" + +## Property [ public $virtual ] + +skipInitializerForProperty(): +ReflectionException: Can not use skipLazyInitialization on virtual property B::$virtual + +setRawValueWithoutLazyInitialization(): +ReflectionException: Can not use setRawValueWithoutLazyInitialization on virtual property B::$virtual + +## Property [ $dynamicProp ] + +skipInitializerForProperty(): +ReflectionException: + +setRawValueWithoutLazyInitialization(): +ReflectionException: diff --git a/Zend/tests/lazy_objects/reflection_to_string_does_not_init.phpt b/Zend/tests/lazy_objects/reflection_to_string_does_not_init.phpt new file mode 100644 index 0000000000000..0b22d564baa76 --- /dev/null +++ b/Zend/tests/lazy_objects/reflection_to_string_does_not_init.phpt @@ -0,0 +1,45 @@ +--TEST-- +Lazy objects: ReflectionObject::__toString() does not trigger initialization +--FILE-- +a = 1; + } +} + +function test(string $name, object $obj) { + printf("# %s\n", $name); + + (new ReflectionObject($obj))->__toString(); + + printf("Initialized:\n"); + var_dump(!(new ReflectionClass($obj))->isUninitializedLazyObject($obj)); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECT-- +# Ghost +Initialized: +bool(false) +# Virtual +Initialized: +bool(false) diff --git a/Zend/tests/lazy_objects/reset_as_lazy_can_reset_initialized_proxies.phpt b/Zend/tests/lazy_objects/reset_as_lazy_can_reset_initialized_proxies.phpt new file mode 100644 index 0000000000000..0ac167724c7da --- /dev/null +++ b/Zend/tests/lazy_objects/reset_as_lazy_can_reset_initialized_proxies.phpt @@ -0,0 +1,55 @@ +--TEST-- +Lazy objects: resetAsLazyProxy() can reset initialized proxies +--FILE-- +newLazyProxy(function ($proxy) { + return new A(1, $proxy); +}); + +print "Init\n"; + +$reflector->initializeLazyObject($proxy); + +var_dump($proxy); + +print "Reset\n"; + +$proxy = $reflector->resetAsLazyProxy($proxy, function () { + return new A(2); +}); + +?> +--EXPECTF-- +Init +lazy proxy object(A)#%d (1) { + ["instance"]=> + object(A)#%d (2) { + ["a"]=> + int(1) + ["proxy"]=> + *RECURSION* + } +} +Reset +string(13) "A::__destruct" +object(A)#%d (2) { + ["a"]=> + int(1) + ["proxy"]=> + object(A)#%d (0) { + } +} diff --git a/Zend/tests/lazy_objects/reset_as_lazy_ignores_additional_props.phpt b/Zend/tests/lazy_objects/reset_as_lazy_ignores_additional_props.phpt new file mode 100644 index 0000000000000..0aa542474a9fd --- /dev/null +++ b/Zend/tests/lazy_objects/reset_as_lazy_ignores_additional_props.phpt @@ -0,0 +1,103 @@ +--TEST-- +Lazy objects: resetAsLazy() ignores additional props +--FILE-- +d = 1; + } + } +} + +$reflector = new ReflectionClass(A::class); + +printf("# B\n"); + +$obj = new B(); +$obj->a = 1; +$obj->b = 2; +$reflector->resetAsLazyGhost($obj, function () {}); +var_dump($obj->b); +var_dump($obj); +var_dump($obj->a); +var_dump($obj); + +printf("# C\n"); + +$obj = new C(); +$obj->a = 1; +$obj->c = 2; +$reflector->resetAsLazyGhost($obj, function () {}); +var_dump($obj->c); +var_dump($obj); +var_dump($obj->a); +var_dump($obj); + +printf("# D\n"); + +$obj = new D(); +$obj->a = 1; +$reflector->resetAsLazyGhost($obj, function ($obj) { + $obj->__construct(true); +}); +var_dump($obj->d ?? 'undef'); +var_dump($obj); +var_dump($obj->a); +var_dump($obj); + +--EXPECTF-- +# B +int(2) +lazy ghost object(B)#%d (1) { + ["b"]=> + int(2) +} +NULL +object(B)#%d (2) { + ["a"]=> + NULL + ["b"]=> + int(2) +} +# C +int(2) +lazy ghost object(C)#%d (1) { + ["c"]=> + int(2) +} +NULL +object(C)#%d (2) { + ["a"]=> + NULL + ["c"]=> + int(2) +} +# D +string(5) "undef" +lazy ghost object(D)#%d (0) { + ["d"]=> + uninitialized(int) +} +NULL +object(D)#%d (2) { + ["a"]=> + NULL + ["d"]=> + int(1) +} diff --git a/Zend/tests/lazy_objects/reset_readonly_001.phpt b/Zend/tests/lazy_objects/reset_readonly_001.phpt new file mode 100644 index 0000000000000..f673d00bb7665 --- /dev/null +++ b/Zend/tests/lazy_objects/reset_readonly_001.phpt @@ -0,0 +1,71 @@ +--TEST-- +Lazy objects: resetAsLazy preserves readonly semantics +--FILE-- +a = $value; + } catch (\Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + if ($setB) { + $this->b = $value; + } + try { + $this->c = $value; + } catch (\Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + } +} + +final class C extends B { +} + + +function test(string $name, object $obj) { + printf("# %s\n", $name); + + $reflector = new ReflectionClass($obj::class); + + $reflector->resetAsLazyGhost($obj, function ($obj) { + $obj->__construct(2, setB: true); + }); + + $reflector->initializeLazyObject($obj); + + var_dump($obj); +} + +$obj = new B(1); +test('B', $obj); + +$obj = new C(1); +test('C', $obj); + +--EXPECTF-- +# B +object(B)#%d (3) { + ["a"]=> + int(2) + ["b"]=> + int(2) + ["c"]=> + int(2) +} +# C +Error: Cannot modify readonly property B::$a +object(C)#%d (3) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(2) +} diff --git a/Zend/tests/lazy_objects/rfc_example_001.phpt b/Zend/tests/lazy_objects/rfc_example_001.phpt new file mode 100644 index 0000000000000..187aa61540cb1 --- /dev/null +++ b/Zend/tests/lazy_objects/rfc_example_001.phpt @@ -0,0 +1,40 @@ +--TEST-- +Lazy objects: RFC example 001 +--FILE-- +foo; + } +} + +$initializer = static function (MyClass $ghost): void { + $ghost->__construct(123); +}; + +$reflector = new ReflectionClass(MyClass::class); +$object = $reflector->newLazyGhost($initializer); + +var_dump($object); +var_dump($object->getFoo()); +var_dump($object); + +?> +--EXPECTF-- +lazy ghost object(MyClass)#%d (0) { + ["foo":"MyClass":private]=> + uninitialized(int) +} +int(123) +object(MyClass)#%d (1) { + ["foo":"MyClass":private]=> + int(123) +} diff --git a/Zend/tests/lazy_objects/rfc_example_002.phpt b/Zend/tests/lazy_objects/rfc_example_002.phpt new file mode 100644 index 0000000000000..e86a25df88718 --- /dev/null +++ b/Zend/tests/lazy_objects/rfc_example_002.phpt @@ -0,0 +1,44 @@ +--TEST-- +Lazy objects: RFC example 002 +--FILE-- +foo; + } +} + +$reflector = new ReflectionClass(MyClass::class); + +$initializer = static function (MyClass $proxy): MyClass { + return new MyClass(123); +}; + +$object = $reflector->newLazyProxy($initializer); + +var_dump($object); +var_dump($object->getFoo()); +var_dump($object); + +?> +--EXPECTF-- +lazy proxy object(MyClass)#%d (0) { + ["foo":"MyClass":private]=> + uninitialized(int) +} +int(123) +lazy proxy object(MyClass)#%d (1) { + ["instance"]=> + object(MyClass)#%d (1) { + ["foo":"MyClass":private]=> + int(123) + } +} diff --git a/Zend/tests/lazy_objects/rfc_example_003.phpt b/Zend/tests/lazy_objects/rfc_example_003.phpt new file mode 100644 index 0000000000000..0463b745d4eed --- /dev/null +++ b/Zend/tests/lazy_objects/rfc_example_003.phpt @@ -0,0 +1,51 @@ +--TEST-- +Lazy objects: RFC example 003 +--FILE-- +resetAsLazyGhost($this, $this->initialize(...), ReflectionClass::SKIP_DESTRUCTOR); + } + + public function initialize() + { + $this->foo = 123; + } + + public function getFoo() + { + return $this->foo; + } + + public function __destruct() + { + var_dump(__METHOD__); + } +} + +$object = new MyLazyClass(); + +var_dump($object); +var_dump($object->getFoo()); +var_dump($object); + +?> +==DONE== +--EXPECTF-- +lazy ghost object(MyLazyClass)#%d (0) { + ["foo":"MyLazyClass":private]=> + uninitialized(int) +} +int(123) +object(MyLazyClass)#%d (1) { + ["foo":"MyLazyClass":private]=> + int(123) +} +==DONE== +string(23) "MyLazyClass::__destruct" diff --git a/Zend/tests/lazy_objects/rfc_example_004.phpt b/Zend/tests/lazy_objects/rfc_example_004.phpt new file mode 100644 index 0000000000000..f2459d9aa6383 --- /dev/null +++ b/Zend/tests/lazy_objects/rfc_example_004.phpt @@ -0,0 +1,69 @@ +--TEST-- +Lazy objects: RFC example 004 +--FILE-- + 'Title', + 'content' => 'Content', + ]; +} + +$reflector = new ReflectionClass(BlogPost::class); +// Callable that retrieves the title and content from the database. +$initializer = function ($blogPost) { + var_dump("initialization"); + $data = loadFromDB(); + $blogPost->title = $data['title']; + $blogPost->content = $data['content']; +}; +$post = $reflector->newLazyGhost($initializer); + +// Without this line, the following call to ReflectionProperty::setValue() would trigger initialization. +$reflector->getProperty('id')->skipLazyInitialization($post); +$reflector->getProperty('id')->setValue($post, 123); + +// Alternatively, one can use this directly: +$reflector->getProperty('id')->setRawValueWithoutLazyInitialization($post, 123); + +var_dump($post); +var_dump($post->id); +var_dump($post->title); +var_dump($post->content); +var_dump($post); + +?> +==DONE== +--EXPECTF-- +lazy ghost object(BlogPost)#%d (1) { + ["id"]=> + int(123) + ["title"]=> + uninitialized(string) + ["content"]=> + uninitialized(string) +} +int(123) +string(14) "initialization" +string(5) "Title" +string(7) "Content" +object(BlogPost)#%d (3) { + ["id"]=> + int(123) + ["title"]=> + string(5) "Title" + ["content"]=> + string(7) "Content" +} +==DONE== diff --git a/Zend/tests/lazy_objects/rfc_example_005.phpt b/Zend/tests/lazy_objects/rfc_example_005.phpt new file mode 100644 index 0000000000000..f8548f36b700d --- /dev/null +++ b/Zend/tests/lazy_objects/rfc_example_005.phpt @@ -0,0 +1,71 @@ +--TEST-- +Lazy objects: RFC example 005 +--FILE-- + 'Title', + 'content' => 'Content', + ]; +} + +$reflector = new ReflectionClass(BlogPost::class); +// Callable that retrieves the title and content from the database. +$initializer = function ($blogPost) { + var_dump("initialization"); + $data = loadFromDB(); + return new BlogPost($blogPost->id, $data['title'], $data['content']); +}; +$post = $reflector->newLazyProxy($initializer); + +// Without this line, the following call to ReflectionProperty::setValue() would trigger initialization. +$reflector->getProperty('id')->skipLazyInitialization($post); +$reflector->getProperty('id')->setValue($post, 123); + +// Alternatively, one can use this directly: +$reflector->getProperty('id')->setRawValueWithoutLazyInitialization($post, 123); + +var_dump($post); +var_dump($post->id); +var_dump($post->title); +var_dump($post->content); +var_dump($post); + +?> +==DONE== +--EXPECTF-- +lazy proxy object(BlogPost)#%d (1) { + ["id"]=> + int(123) + ["title"]=> + uninitialized(string) + ["content"]=> + uninitialized(string) +} +int(123) +string(14) "initialization" +string(5) "Title" +string(7) "Content" +lazy proxy object(BlogPost)#%d (1) { + ["instance"]=> + object(BlogPost)#%d (3) { + ["id"]=> + int(123) + ["title"]=> + string(5) "Title" + ["content"]=> + string(7) "Content" + } +} +==DONE== diff --git a/Zend/tests/lazy_objects/rfc_example_006.phpt b/Zend/tests/lazy_objects/rfc_example_006.phpt new file mode 100644 index 0000000000000..c467567186495 --- /dev/null +++ b/Zend/tests/lazy_objects/rfc_example_006.phpt @@ -0,0 +1,64 @@ +--TEST-- +Lazy objects: RFC example 006 +--FILE-- +newLazyGhost(function ($object2) { + $object2->propB = 'value'; + throw new \Exception('initializer exception'); +}); +$reflector->getProperty('propA')->setRawValueWithoutLazyInitialization($object2, 'object-2'); + +$object1 = $reflector->newLazyGhost(function ($object1) use ($object2) { + $object1->propB = 'updated'; + $object1->propB = $object2->propB; +}); +$reflector->getProperty('propA')->setRawValueWithoutLazyInitialization($object1, 'object-1'); + +// Both objects are uninitalized at this point + +var_dump($object1); +var_dump($object2); + +try { + var_dump($object1->propB); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +// The state of both objects is unchanged + +var_dump($object1); +var_dump($object2); + +?> +==DONE== +--EXPECTF-- +lazy ghost object(MyClass)#%d (1) { + ["propA"]=> + string(8) "object-1" +} +lazy ghost object(MyClass)#%d (1) { + ["propA"]=> + string(8) "object-2" +} +initializer exception +lazy ghost object(MyClass)#%d (1) { + ["propA"]=> + string(8) "object-1" +} +lazy ghost object(MyClass)#%d (1) { + ["propA"]=> + string(8) "object-2" +} +==DONE== diff --git a/Zend/tests/lazy_objects/rfc_example_007.phpt b/Zend/tests/lazy_objects/rfc_example_007.phpt new file mode 100644 index 0000000000000..5310345428556 --- /dev/null +++ b/Zend/tests/lazy_objects/rfc_example_007.phpt @@ -0,0 +1,31 @@ +--TEST-- +Lazy objects: RFC example 007 +--FILE-- +resetAsLazyGhost($object, function () {}); +var_dump($id === spl_object_id($object)); +var_dump($ref->get() === $object); + +$reflector->initializeLazyObject($object); +var_dump($id === spl_object_id($object)); +var_dump($ref->get() === $object); + +?> +==DONE== +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +==DONE== diff --git a/Zend/tests/lazy_objects/rfc_example_008.phpt b/Zend/tests/lazy_objects/rfc_example_008.phpt new file mode 100644 index 0000000000000..7cbbcb21c5811 --- /dev/null +++ b/Zend/tests/lazy_objects/rfc_example_008.phpt @@ -0,0 +1,25 @@ +--TEST-- +Lazy objects: RFC example 008 +--FILE-- +newLazyGhost(function () { + throw new \Exception('initialization'); +}); + +$reflector->getProperty('id')->skipLazyInitialization($object); + +$object->id = 1; +var_dump($object->id); + +?> +==DONE== +--EXPECT-- +int(1) +==DONE== diff --git a/Zend/tests/lazy_objects/rfc_example_009.phpt b/Zend/tests/lazy_objects/rfc_example_009.phpt new file mode 100644 index 0000000000000..ccf7f53e6b260 --- /dev/null +++ b/Zend/tests/lazy_objects/rfc_example_009.phpt @@ -0,0 +1,40 @@ +--TEST-- +Lazy objects: RFC example 009 +--FILE-- +connect(); + } + public function __destruct() { + var_dump(__METHOD__); + $this->close(); + } + public function connect() { + } + public function close() { + } +} + +$connection = new Connection(); + +$reflector = new ReflectionClass(Connection::class); + +print "Reset non-lazy\n"; +// Calls destructor +$reflector->resetAsLazyGhost($connection, function () { + var_dump("initialization"); +}); + +print "Release non-initialized\n"; +$connection = null; // Does not call destructor (object is not initialized) + +?> +==DONE== +--EXPECT-- +Reset non-lazy +string(22) "Connection::__destruct" +Release non-initialized +==DONE== diff --git a/Zend/tests/lazy_objects/rfc_example_010.phpt b/Zend/tests/lazy_objects/rfc_example_010.phpt new file mode 100644 index 0000000000000..3c578a883ea90 --- /dev/null +++ b/Zend/tests/lazy_objects/rfc_example_010.phpt @@ -0,0 +1,25 @@ +--TEST-- +Lazy objects: RFC example 010 +--FILE-- +newLazyGhost(function () {}); + +$reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, 'value'); + +var_dump($obj); + +?> +==DONE== +--EXPECTF-- +lazy ghost object(MyClass)#%d (1) { + ["a"]=> + string(5) "value" +} +==DONE== diff --git a/Zend/tests/lazy_objects/rfc_example_011.phpt b/Zend/tests/lazy_objects/rfc_example_011.phpt new file mode 100644 index 0000000000000..2dc50b1a33ff3 --- /dev/null +++ b/Zend/tests/lazy_objects/rfc_example_011.phpt @@ -0,0 +1,81 @@ +--TEST-- +Lazy objects: RFC example 011 +--FILE-- +name; + } + + public function getEmail() + { + return $this->email; + } +} + +// ORM code + +class EntityManager +{ + public function getReference(string $class, int $id) + { + // The ReflectionClass and ReflectionProperty instances are cached in practice + $reflector = new ReflectionClass($class); + + $entity = $reflector->newLazyGhost(function ($entity) use ($class, $id, $reflector) { + $data = $this->loadFromDatabase($class, $id); + $reflector->getProperty('name')->setValue($entity, $data['name']); + $reflector->getProperty('email')->setValue($entity, $data['email']); + }); + + // id is already known and can be accessed without triggering initialization + $reflector->getProperty('id')->setRawValueWithoutLazyInitialization($entity, $id); + + return $entity; + } + + public function loadFromDatabase($id) + { + return [ + 'name' => 'Example', + 'email' => 'example@example.com', + ]; + } +} + +$em = new EntityManager(); +$blogPost = $em->getReference(BlogPost::class, 123); +var_dump($blogPost); +var_dump($blogPost->getName()); +var_dump($blogPost); + +?> +==DONE== +--EXPECTF-- +lazy ghost object(BlogPost)#%d (1) { + ["id":"BlogPost":private]=> + int(123) + ["name":"BlogPost":private]=> + uninitialized(string) + ["email":"BlogPost":private]=> + uninitialized(string) +} +string(7) "Example" +object(BlogPost)#%d (3) { + ["id":"BlogPost":private]=> + int(123) + ["name":"BlogPost":private]=> + string(7) "Example" + ["email":"BlogPost":private]=> + string(19) "example@example.com" +} +==DONE== diff --git a/Zend/tests/lazy_objects/rfc_example_012.phpt b/Zend/tests/lazy_objects/rfc_example_012.phpt new file mode 100644 index 0000000000000..14b07d3bd65e4 --- /dev/null +++ b/Zend/tests/lazy_objects/rfc_example_012.phpt @@ -0,0 +1,80 @@ +--TEST-- +Lazy objects: RFC example 012 +--FILE-- +hostname, $this->credentials); + } +} + +class Client +{ + public function __construct( + private string $hostname, + private string $credentials, + ) {} + + public function doSomething() + { + printf("doSomething() (hostname: %s)\n", $this->hostname); + } +} + +// Symfony code + +class Container +{ + public function getClientFactoryService(): ClientFactory + { + return new ClientFactory('127.0.0.1', 'secret'); + } + + public function getClientService(): Client + { + $reflector = new ReflectionClass(Client::class); + + $client = $reflector->newLazyProxy(function () { + $clientFactory = $this->getClientFactoryService(); + return $clientFactory->createClient(); + }); + + return $client; + } +} + +$container = new Container(); +$service = $container->getClientService(); +var_dump($service); +$service->doSomething(); +var_dump($service); + +?> +==DONE== +--EXPECTF-- +lazy proxy object(Client)#%d (0) { + ["hostname":"Client":private]=> + uninitialized(string) + ["credentials":"Client":private]=> + uninitialized(string) +} +doSomething() (hostname: 127.0.0.1) +lazy proxy object(Client)#%d (1) { + ["instance"]=> + object(Client)#%d (2) { + ["hostname":"Client":private]=> + string(9) "127.0.0.1" + ["credentials":"Client":private]=> + string(6) "secret" + } +} +==DONE== diff --git a/Zend/tests/lazy_objects/serialize_001.phpt b/Zend/tests/lazy_objects/serialize_001.phpt new file mode 100644 index 0000000000000..2203f83760bcc --- /dev/null +++ b/Zend/tests/lazy_objects/serialize_001.phpt @@ -0,0 +1,44 @@ +--TEST-- +Lazy objects: serialize initializes object by default +--FILE-- +a = 1; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump(serialize($obj)); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECT-- +# Ghost: +string(11) "initializer" +string(14) "C::__construct" +string(24) "O:1:"C":1:{s:1:"a";i:1;}" +# Virtual: +string(11) "initializer" +string(14) "C::__construct" +string(24) "O:1:"C":1:{s:1:"a";i:1;}" diff --git a/Zend/tests/lazy_objects/serialize_002.phpt b/Zend/tests/lazy_objects/serialize_002.phpt new file mode 100644 index 0000000000000..9b664f92dbf8f --- /dev/null +++ b/Zend/tests/lazy_objects/serialize_002.phpt @@ -0,0 +1,47 @@ +--TEST-- +Lazy objects: serialize initializes object by default (properties hashtable) +--FILE-- +a = 1; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + // Builds properties hashtable + get_object_vars($obj); + + var_dump(serialize($obj)); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECT-- +# Ghost: +string(11) "initializer" +string(14) "C::__construct" +string(24) "O:1:"C":1:{s:1:"a";i:1;}" +# Virtual: +string(11) "initializer" +string(14) "C::__construct" +string(24) "O:1:"C":1:{s:1:"a";i:1;}" diff --git a/Zend/tests/lazy_objects/serialize_003.phpt b/Zend/tests/lazy_objects/serialize_003.phpt new file mode 100644 index 0000000000000..71da496fb5aba --- /dev/null +++ b/Zend/tests/lazy_objects/serialize_003.phpt @@ -0,0 +1,52 @@ +--TEST-- +Lazy objects: serialize does not initializes object if flag is set +--FILE-- +setRawValueWithoutLazyInitialization($obj, 1); + + $serialized = serialize($obj); + $unserialized = unserialize($serialized); + var_dump($serialized, $unserialized); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); +}, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); +}, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +string(24) "O:1:"C":1:{s:1:"b";i:1;}" +object(C)#%d (1) { + ["a"]=> + uninitialized(int) + ["b"]=> + int(1) +} +# Virtual: +string(24) "O:1:"C":1:{s:1:"b";i:1;}" +object(C)#%d (1) { + ["a"]=> + uninitialized(int) + ["b"]=> + int(1) +} diff --git a/Zend/tests/lazy_objects/serialize_004.phpt b/Zend/tests/lazy_objects/serialize_004.phpt new file mode 100644 index 0000000000000..70d3fe7dfc8b5 --- /dev/null +++ b/Zend/tests/lazy_objects/serialize_004.phpt @@ -0,0 +1,55 @@ +--TEST-- +Lazy objects: serialize does not initializes object if flag is set (properties hashtable) +--FILE-- +setRawValueWithoutLazyInitialization($obj, 1); + + // Builds properties hashtable + get_mangled_object_vars($obj); + + $serialized = serialize($obj); + $unserialized = unserialize($serialized); + var_dump($serialized, $unserialized); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); +}, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); +}, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +string(24) "O:1:"C":1:{s:1:"b";i:1;}" +object(C)#%d (1) { + ["a"]=> + uninitialized(int) + ["b"]=> + int(1) +} +# Virtual: +string(24) "O:1:"C":1:{s:1:"b";i:1;}" +object(C)#%d (1) { + ["a"]=> + uninitialized(int) + ["b"]=> + int(1) +} diff --git a/Zend/tests/lazy_objects/serialize_005.phpt b/Zend/tests/lazy_objects/serialize_005.phpt new file mode 100644 index 0000000000000..e9817b6a3a771 --- /dev/null +++ b/Zend/tests/lazy_objects/serialize_005.phpt @@ -0,0 +1,48 @@ +--TEST-- +Lazy objects: serialize does not force initialization of object if the __serialize method is used +--FILE-- +newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +string(12) "O:1:"C":0:{}" +object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +# Virtual: +string(12) "O:1:"C":0:{}" +object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} diff --git a/Zend/tests/lazy_objects/serialize_006.phpt b/Zend/tests/lazy_objects/serialize_006.phpt new file mode 100644 index 0000000000000..4c965c0fe934e --- /dev/null +++ b/Zend/tests/lazy_objects/serialize_006.phpt @@ -0,0 +1,53 @@ +--TEST-- +Lazy objects: __serialize may initialize object +--FILE-- + $this->a]; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + $serialized = serialize($obj); + $unserialized = unserialize($serialized); + var_dump($serialized, $unserialized); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 1; +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + $c = new c(); + $c->a = 1; + return $c; +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +string(11) "initializer" +string(24) "O:1:"C":1:{s:1:"a";i:1;}" +object(C)#%d (1) { + ["a"]=> + int(1) +} +# Virtual: +string(11) "initializer" +string(24) "O:1:"C":1:{s:1:"a";i:1;}" +object(C)#%d (1) { + ["a"]=> + int(1) +} diff --git a/Zend/tests/lazy_objects/serialize_007.phpt b/Zend/tests/lazy_objects/serialize_007.phpt new file mode 100644 index 0000000000000..d817aaf5279be --- /dev/null +++ b/Zend/tests/lazy_objects/serialize_007.phpt @@ -0,0 +1,53 @@ +--TEST-- +Lazy objects: serialize initializes object by default if the __sleep method is used +--FILE-- +newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 1; +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + $c = new C(); + $c->a = 1; + return $c; +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +string(11) "initializer" +string(24) "O:1:"C":1:{s:1:"a";i:1;}" +object(C)#%d (1) { + ["a"]=> + int(1) +} +# Virtual: +string(11) "initializer" +string(24) "O:1:"C":1:{s:1:"a";i:1;}" +object(C)#%d (1) { + ["a"]=> + int(1) +} diff --git a/Zend/tests/lazy_objects/serialize_008.phpt b/Zend/tests/lazy_objects/serialize_008.phpt new file mode 100644 index 0000000000000..4ef54498e5b5b --- /dev/null +++ b/Zend/tests/lazy_objects/serialize_008.phpt @@ -0,0 +1,49 @@ +--TEST-- +Lazy objects: serialize does not initializes object with __sleep method if flag is set +--FILE-- +newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 1; +}, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 1; +}, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +string(12) "O:1:"C":0:{}" +object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +# Virtual: +string(12) "O:1:"C":0:{}" +object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} diff --git a/Zend/tests/lazy_objects/serialize_009.phpt b/Zend/tests/lazy_objects/serialize_009.phpt new file mode 100644 index 0000000000000..af1876afbddf3 --- /dev/null +++ b/Zend/tests/lazy_objects/serialize_009.phpt @@ -0,0 +1,56 @@ +--TEST-- +Lazy objects: __sleep may initialize object +--FILE-- +a); + return ['a']; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + $serialized = serialize($obj); + $unserialized = unserialize($serialized); + var_dump($serialized, $unserialized); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->a = 1; +}, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + $c = new C(); + $c->a = 1; + return $c; +}, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +string(11) "initializer" +int(1) +string(24) "O:1:"C":1:{s:1:"a";i:1;}" +object(C)#%d (1) { + ["a"]=> + int(1) +} +# Virtual: +string(11) "initializer" +int(1) +string(24) "O:1:"C":1:{s:1:"a";i:1;}" +object(C)#%d (1) { + ["a"]=> + int(1) +} diff --git a/Zend/tests/lazy_objects/serialize_010.phpt b/Zend/tests/lazy_objects/serialize_010.phpt new file mode 100644 index 0000000000000..6cc46513a0f6b --- /dev/null +++ b/Zend/tests/lazy_objects/serialize_010.phpt @@ -0,0 +1,47 @@ +--TEST-- +Lazy objects: serialize during hook initializes object by default +--FILE-- +a = $value; } + } + public function __construct() { + var_dump(__METHOD__); + $this->a = 1; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj->a); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECT-- +# Ghost: +string(11) "initializer" +string(14) "C::__construct" +string(24) "O:1:"C":1:{s:1:"a";i:1;}" +# Virtual: +string(11) "initializer" +string(14) "C::__construct" +string(24) "O:1:"C":1:{s:1:"a";i:1;}" diff --git a/Zend/tests/lazy_objects/set_raw_value_001.phpt b/Zend/tests/lazy_objects/set_raw_value_001.phpt new file mode 100644 index 0000000000000..807476d70729a --- /dev/null +++ b/Zend/tests/lazy_objects/set_raw_value_001.phpt @@ -0,0 +1,47 @@ +--TEST-- +Lazy objects: setRawValueWithoutLazyInitialization() sets value +--FILE-- +getProperty('a')->setRawValueWithoutLazyInitialization($obj, 'test'); + + var_dump(!$reflector->isUninitializedLazyObject($obj)); + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function () { + throw new \Exception('initializer'); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + throw new \Exception('initializer'); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +bool(false) +lazy ghost object(C)#%d (1) { + ["a"]=> + string(4) "test" +} +# Proxy +bool(false) +lazy proxy object(C)#%d (1) { + ["a"]=> + string(4) "test" +} diff --git a/Zend/tests/lazy_objects/set_raw_value_002.phpt b/Zend/tests/lazy_objects/set_raw_value_002.phpt new file mode 100644 index 0000000000000..7bd6261519ec8 --- /dev/null +++ b/Zend/tests/lazy_objects/set_raw_value_002.phpt @@ -0,0 +1,50 @@ +--TEST-- +Lazy objects: setRawValueWithoutLazyInitialization() skips hooks +--FILE-- +a = $value; } + get { return $this->a; } + } + public $b; +} + +function test(string $name, object $obj) { + printf("# %s\n", $name); + + $reflector = new ReflectionClass(C::class); + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, 'test'); + + var_dump(!$reflector->isUninitializedLazyObject($obj)); + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function () { + throw new \Exception('initializer'); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + throw new \Exception('initializer'); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +bool(false) +lazy ghost object(C)#%d (1) { + ["a"]=> + string(4) "test" +} +# Proxy +bool(false) +lazy proxy object(C)#%d (1) { + ["a"]=> + string(4) "test" +} diff --git a/Zend/tests/lazy_objects/set_raw_value_003.phpt b/Zend/tests/lazy_objects/set_raw_value_003.phpt new file mode 100644 index 0000000000000..a3f0002c9cd6f --- /dev/null +++ b/Zend/tests/lazy_objects/set_raw_value_003.phpt @@ -0,0 +1,52 @@ +--TEST-- +Lazy objects: setRawValueWithoutLazyInitialization() may realize object if last lazy prop +--FILE-- +getProperty('a')->setRawValueWithoutLazyInitialization($obj, 'test'); + $reflector->getProperty('b')->setRawValueWithoutLazyInitialization($obj, 'test'); + + var_dump(!$reflector->isUninitializedLazyObject($obj)); + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function () { + throw new \Exception('initializer'); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + throw new \Exception('initializer'); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +bool(true) +object(C)#%d (2) { + ["a"]=> + string(4) "test" + ["b"]=> + string(4) "test" +} +# Proxy +bool(true) +object(C)#%d (2) { + ["a"]=> + string(4) "test" + ["b"]=> + string(4) "test" +} diff --git a/Zend/tests/lazy_objects/set_raw_value_004.phpt b/Zend/tests/lazy_objects/set_raw_value_004.phpt new file mode 100644 index 0000000000000..10a335f8fe5f0 --- /dev/null +++ b/Zend/tests/lazy_objects/set_raw_value_004.phpt @@ -0,0 +1,51 @@ +--TEST-- +Lazy objects: setRawValueWithoutLazyInitialization() does not call __set() +--FILE-- +getProperty('a')->setRawValueWithoutLazyInitialization($obj, 'test'); + + var_dump(!$reflector->isUninitializedLazyObject($obj)); + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function () { + throw new \Exception('initializer'); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + throw new \Exception('initializer'); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +bool(false) +lazy ghost object(C)#%d (1) { + ["a"]=> + string(4) "test" +} +# Proxy +bool(false) +lazy proxy object(C)#%d (1) { + ["a"]=> + string(4) "test" +} diff --git a/Zend/tests/lazy_objects/set_raw_value_005.phpt b/Zend/tests/lazy_objects/set_raw_value_005.phpt new file mode 100644 index 0000000000000..1c8eac82880c0 --- /dev/null +++ b/Zend/tests/lazy_objects/set_raw_value_005.phpt @@ -0,0 +1,68 @@ +--TEST-- +Lazy objects: setRawValueWithoutLazyInitialization() may trigger initialization via side effects (__toString()) +--FILE-- +a = 'a'; + $this->b = 'b'; + } + public string $a; + public string $b; +} + +function test(string $name, object $obj) { + printf("# %s\n", $name); + + $reflector = new ReflectionClass(C::class); + + $value = new class($obj) { + function __construct(public object $obj) {} + function __toString() { + return $this->obj->b; + } + }; + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, $value); + + var_dump(!$reflector->isUninitializedLazyObject($obj)); + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function ($obj) { + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + return new C(); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +C::__construct +bool(true) +object(C)#%d (2) { + ["a"]=> + string(1) "b" + ["b"]=> + string(1) "b" +} +# Proxy +C::__construct +bool(true) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["a"]=> + string(1) "a" + ["b"]=> + string(1) "b" + } +} diff --git a/Zend/tests/lazy_objects/set_raw_value_006.phpt b/Zend/tests/lazy_objects/set_raw_value_006.phpt new file mode 100644 index 0000000000000..96bc8054ed49b --- /dev/null +++ b/Zend/tests/lazy_objects/set_raw_value_006.phpt @@ -0,0 +1,71 @@ +--TEST-- +Lazy objects: setRawValueWithoutLazyInitialization() may trigger initialization via side effects (__destruct()) +--FILE-- +a = 'a'; + $this->b = 'b'; + } + public $a; + public $b; +} + +function test(string $name, object $obj) { + printf("# %s\n", $name); + + $reflector = new ReflectionClass(C::class); + + $value = new class($obj) { + function __construct(public object $obj) {} + function __destruct() { + $this->obj->b = ''; + } + }; + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, $value); + $value = null; + + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, new stdClass); + + var_dump(!$reflector->isUninitializedLazyObject($obj)); + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function ($obj) { + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + return new C(); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +C::__construct +bool(true) +object(C)#%d (2) { + ["a"]=> + string(1) "a" + ["b"]=> + string(0) "" +} +# Proxy +C::__construct +bool(true) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["a"]=> + string(1) "a" + ["b"]=> + string(0) "" + } +} diff --git a/Zend/tests/lazy_objects/set_raw_value_007.phpt b/Zend/tests/lazy_objects/set_raw_value_007.phpt new file mode 100644 index 0000000000000..caa5211f371a5 --- /dev/null +++ b/Zend/tests/lazy_objects/set_raw_value_007.phpt @@ -0,0 +1,54 @@ +--TEST-- +Lazy objects: setRawValueWithoutLazyInitialization() is allowed on initialized objects +--FILE-- +initializeLazyObject($obj); + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, 'test'); + + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function ($obj) { + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + return new C(); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +object(C)#%d (2) { + ["a"]=> + string(4) "test" + ["b"]=> + NULL +} +# Proxy +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["a"]=> + NULL + ["b"]=> + NULL + } +} diff --git a/Zend/tests/lazy_objects/set_raw_value_008.phpt b/Zend/tests/lazy_objects/set_raw_value_008.phpt new file mode 100644 index 0000000000000..9151e58f3fc65 --- /dev/null +++ b/Zend/tests/lazy_objects/set_raw_value_008.phpt @@ -0,0 +1,43 @@ +--TEST-- +Lazy objects: setRawValueWithoutLazyInitialization() can not be called on dynamic properties +--FILE-- +dyn = 1; + $propReflector = new ReflectionProperty($c, 'dyn'); + + try { + $propReflector->setRawValueWithoutLazyInitialization($obj, 'test'); + } catch (\ReflectionException $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function () { + throw new \Exception('initializer'); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + throw new \Exception('initializer'); +}); + +test('Proxy', $obj); + +?> +--EXPECT-- +# Ghost +ReflectionException: Can not use setRawValueWithoutLazyInitialization on dynamic property C::$dyn +# Proxy +ReflectionException: Can not use setRawValueWithoutLazyInitialization on dynamic property C::$dyn diff --git a/Zend/tests/lazy_objects/set_raw_value_009.phpt b/Zend/tests/lazy_objects/set_raw_value_009.phpt new file mode 100644 index 0000000000000..1e4a7ade935ad --- /dev/null +++ b/Zend/tests/lazy_objects/set_raw_value_009.phpt @@ -0,0 +1,54 @@ +--TEST-- +Lazy objects: setRawValueWithoutLazyInitialization() preserves readonly semantics +--FILE-- +getProperty('a')->setRawValueWithoutLazyInitialization($obj, 1); + try { + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, 2); + } catch (\Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + + var_dump(!$reflector->isUninitializedLazyObject($obj)); + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function () { + throw new \Exception('initializer'); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + throw new \Exception('initializer'); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +Error: Cannot modify readonly property C::$a +bool(false) +lazy ghost object(C)#%d (1) { + ["a"]=> + int(1) +} +# Proxy +Error: Cannot modify readonly property C::$a +bool(false) +lazy proxy object(C)#%d (1) { + ["a"]=> + int(1) +} diff --git a/Zend/tests/lazy_objects/skip_initialization_001.phpt b/Zend/tests/lazy_objects/skip_initialization_001.phpt new file mode 100644 index 0000000000000..15859a79e74a4 --- /dev/null +++ b/Zend/tests/lazy_objects/skip_initialization_001.phpt @@ -0,0 +1,59 @@ +--TEST-- +Lazy objects: skipLazyInitialization() marks property as non-lazy and sets default value if any +--FILE-- +getProperty('a')->skipLazyInitialization($obj); + $reflector->getProperty('b')->skipLazyInitialization($obj); + + var_dump($obj->a); + var_dump($obj->b); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function () { + throw new \Exception('initializer'); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + throw new \Exception('initializer'); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +NULL +int(1) +bool(false) +lazy ghost object(C)#%d (2) { + ["a"]=> + NULL + ["b"]=> + int(1) +} +# Proxy +NULL +int(1) +bool(false) +lazy proxy object(C)#%d (2) { + ["a"]=> + NULL + ["b"]=> + int(1) +} diff --git a/Zend/tests/lazy_objects/skip_initialization_002.phpt b/Zend/tests/lazy_objects/skip_initialization_002.phpt new file mode 100644 index 0000000000000..779e931773b06 --- /dev/null +++ b/Zend/tests/lazy_objects/skip_initialization_002.phpt @@ -0,0 +1,53 @@ +--TEST-- +Lazy objects: skipLazyInitialization() skips hooks +--FILE-- +a = $value; } + get { return $this->a; } + } + public $b; +} + +function test(string $name, object $obj) { + printf("# %s\n", $name); + + $reflector = new ReflectionClass(C::class); + $reflector->getProperty('a')->skipLazyInitialization($obj); + + var_dump($obj->a); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function () { + throw new \Exception('initializer'); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + throw new \Exception('initializer'); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +int(1) +bool(false) +lazy ghost object(C)#%d (1) { + ["a"]=> + int(1) +} +# Proxy +int(1) +bool(false) +lazy proxy object(C)#%d (1) { + ["a"]=> + int(1) +} diff --git a/Zend/tests/lazy_objects/skip_initialization_003.phpt b/Zend/tests/lazy_objects/skip_initialization_003.phpt new file mode 100644 index 0000000000000..084a3993876f4 --- /dev/null +++ b/Zend/tests/lazy_objects/skip_initialization_003.phpt @@ -0,0 +1,52 @@ +--TEST-- +Lazy objects: skipLazyInitialization() may realize object if last lazy prop +--FILE-- +getProperty('a')->skipLazyInitialization($obj); + $reflector->getProperty('b')->skipLazyInitialization($obj); + + var_dump(!$reflector->isUninitializedLazyObject($obj)); + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function () { + throw new \Exception('initializer'); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + throw new \Exception('initializer'); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +bool(true) +object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + NULL +} +# Proxy +bool(true) +object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + NULL +} diff --git a/Zend/tests/lazy_objects/skip_initialization_004.phpt b/Zend/tests/lazy_objects/skip_initialization_004.phpt new file mode 100644 index 0000000000000..761a2923e69a2 --- /dev/null +++ b/Zend/tests/lazy_objects/skip_initialization_004.phpt @@ -0,0 +1,54 @@ +--TEST-- +Lazy objects: skipLazyInitialization() does not call __set() +--FILE-- +getProperty('a')->skipLazyInitialization($obj); + + var_dump($obj->a); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function () { + throw new \Exception('initializer'); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + throw new \Exception('initializer'); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +int(1) +bool(false) +lazy ghost object(C)#%d (1) { + ["a"]=> + int(1) +} +# Proxy +int(1) +bool(false) +lazy proxy object(C)#%d (1) { + ["a"]=> + int(1) +} diff --git a/Zend/tests/lazy_objects/skip_initialization_005.phpt b/Zend/tests/lazy_objects/skip_initialization_005.phpt new file mode 100644 index 0000000000000..2244020fb6100 --- /dev/null +++ b/Zend/tests/lazy_objects/skip_initialization_005.phpt @@ -0,0 +1,54 @@ +--TEST-- +Lazy objects: skipLazyInitialization() has no effect on non-lazy properties +--FILE-- +getProperty('a')->skipLazyInitialization($obj); + + $obj->a = 2; + + $reflector->getProperty('a')->skipLazyInitialization($obj); + + var_dump($obj->a); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function () { + throw new \Exception('initializer'); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + throw new \Exception('initializer'); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +int(2) +bool(false) +lazy ghost object(C)#%d (1) { + ["a"]=> + int(2) +} +# Proxy +int(2) +bool(false) +lazy proxy object(C)#%d (1) { + ["a"]=> + int(2) +} diff --git a/Zend/tests/lazy_objects/skip_initialization_006.phpt b/Zend/tests/lazy_objects/skip_initialization_006.phpt new file mode 100644 index 0000000000000..bf8ff2094ca15 --- /dev/null +++ b/Zend/tests/lazy_objects/skip_initialization_006.phpt @@ -0,0 +1,61 @@ +--TEST-- +Lazy objects: skipLazyInitialization() has no effect on initialized objects +--FILE-- +a = 2; + } + public $a = 1; + public $b; +} + +function test(string $name, object $obj) { + printf("# %s\n", $name); + + $reflector = new ReflectionClass(C::class); + $reflector->initializeLazyObject($obj); + $reflector->getProperty('a')->skipLazyInitialization($obj); + + var_dump($obj->a); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function ($obj) { + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + return new C(); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +int(2) +bool(true) +object(C)#%d (2) { + ["a"]=> + int(2) + ["b"]=> + NULL +} +# Proxy +int(1) +bool(true) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["a"]=> + int(2) + ["b"]=> + NULL + } +} diff --git a/Zend/tests/lazy_objects/skip_initialization_007.phpt b/Zend/tests/lazy_objects/skip_initialization_007.phpt new file mode 100644 index 0000000000000..dcb94f90b82ac --- /dev/null +++ b/Zend/tests/lazy_objects/skip_initialization_007.phpt @@ -0,0 +1,75 @@ +--TEST-- +Lazy objects: skipLazyInitialization() preserves readonly semantics +--FILE-- +a = 1; + } + public readonly int $a; + public $b; +} + +function test(string $name, object $obj) { + printf("# %s\n", $name); + + $reflector = new ReflectionClass(C::class); + $reflector->getProperty('a')->skipLazyInitialization($obj); + + try { + var_dump($obj->a); + } catch (Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + var_dump(!$reflector->isUninitializedLazyObject($obj)); + var_dump($obj); + + $reflector->initializeLazyObject($obj); + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function ($obj) { + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + return new C(); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +Error: Typed property C::$a must not be accessed before initialization +bool(false) +lazy ghost object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + NULL +} +# Proxy +Error: Typed property C::$a must not be accessed before initialization +bool(false) +lazy proxy object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + NULL + } +} diff --git a/Zend/tests/lazy_objects/skip_initialization_008.phpt b/Zend/tests/lazy_objects/skip_initialization_008.phpt new file mode 100644 index 0000000000000..cdb1b66543d65 --- /dev/null +++ b/Zend/tests/lazy_objects/skip_initialization_008.phpt @@ -0,0 +1,76 @@ +--TEST-- +Lazy objects: setRawValueWithoutLazyInitialization() preserves readonly semantics +--FILE-- +a = 1; + } catch (Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + } + public readonly int $a; + public $b; +} + +function test(string $name, object $obj) { + printf("# %s\n", $name); + + $reflector = new ReflectionClass(C::class); + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, 2); + + var_dump($obj->a); + var_dump(!$reflector->isUninitializedLazyObject($obj)); + var_dump($obj); + + $reflector->initializeLazyObject($obj); + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function ($obj) { + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + return new C(); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +int(2) +bool(false) +lazy ghost object(C)#%d (1) { + ["a"]=> + int(2) +} +Error: Cannot modify readonly property C::$a +object(C)#%d (2) { + ["a"]=> + int(2) + ["b"]=> + NULL +} +# Proxy +int(2) +bool(false) +lazy proxy object(C)#%d (1) { + ["a"]=> + int(2) +} +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + NULL + } +} diff --git a/Zend/tests/lazy_objects/skip_initialization_009.phpt b/Zend/tests/lazy_objects/skip_initialization_009.phpt new file mode 100644 index 0000000000000..d6eb417a15760 --- /dev/null +++ b/Zend/tests/lazy_objects/skip_initialization_009.phpt @@ -0,0 +1,67 @@ +--TEST-- +Lazy objects: setRawValueWithoutLazyInitialization() leaves property as lazy if exception prevents update +--FILE-- +getProperty('a')->setRawValueWithoutLazyInitialization($obj, new stdClass); + } catch (Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + + // Prop is still lazy: This triggers initialization + $obj->a = 1; + var_dump(!$reflector->isUninitializedLazyObject($obj)); + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function ($obj) { + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + return new C(); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +TypeError: Cannot assign stdClass to property C::$a of type int +C::__construct +bool(true) +object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + NULL +} +# Proxy +TypeError: Cannot assign stdClass to property C::$a of type int +C::__construct +bool(true) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + NULL + } +} diff --git a/Zend/tests/lazy_objects/skip_initialization_010.phpt b/Zend/tests/lazy_objects/skip_initialization_010.phpt new file mode 100644 index 0000000000000..74e12cb3629f8 --- /dev/null +++ b/Zend/tests/lazy_objects/skip_initialization_010.phpt @@ -0,0 +1,43 @@ +--TEST-- +Lazy objects: skipLazyInitialization() can not be used on dynamic properties +--FILE-- +dyn = 1; + $propReflector = new ReflectionProperty($c, 'dyn'); + + try { + $propReflector->skipLazyInitialization($obj); + } catch (\ReflectionException $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function () { + throw new \Exception('initializer'); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + throw new \Exception('initializer'); +}); + +test('Proxy', $obj); + +?> +--EXPECT-- +# Ghost +ReflectionException: Can not use skipLazyInitialization on dynamic property C::$dyn +# Proxy +ReflectionException: Can not use skipLazyInitialization on dynamic property C::$dyn diff --git a/Zend/tests/lazy_objects/unclean_shutdown.phpt b/Zend/tests/lazy_objects/unclean_shutdown.phpt new file mode 100644 index 0000000000000..a5effe34642f9 --- /dev/null +++ b/Zend/tests/lazy_objects/unclean_shutdown.phpt @@ -0,0 +1,17 @@ +--TEST-- +Lazy objects: unclean shutdown +--FILE-- +newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + trigger_error('Fatal', E_USER_ERROR); +}); + +var_dump($obj->a); +--EXPECTF-- +Fatal error: Fatal in %s on line %d diff --git a/Zend/tests/lazy_objects/unset_001.phpt b/Zend/tests/lazy_objects/unset_001.phpt new file mode 100644 index 0000000000000..c7f12cafd01d4 --- /dev/null +++ b/Zend/tests/lazy_objects/unset_001.phpt @@ -0,0 +1,66 @@ +--TEST-- +Lazy objects: unset of undefined property initializes object +--FILE-- +a = $a; + $this->b = 2; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + unset($obj->a); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(1); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(1); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +object(C)#%d (1) { + ["b"]=> + int(2) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["b"]=> + int(2) + } +} diff --git a/Zend/tests/lazy_objects/unset_003.phpt b/Zend/tests/lazy_objects/unset_003.phpt new file mode 100644 index 0000000000000..2d08d94485d54 --- /dev/null +++ b/Zend/tests/lazy_objects/unset_003.phpt @@ -0,0 +1,60 @@ +--TEST-- +Lazy objects: unset of magic property may not initialize object +--FILE-- +b = 2; + } + + public function __unset($name) { + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + unset($obj->a); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(1); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(1); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} diff --git a/Zend/tests/lazy_objects/unset_004.phpt b/Zend/tests/lazy_objects/unset_004.phpt new file mode 100644 index 0000000000000..be63629f532a2 --- /dev/null +++ b/Zend/tests/lazy_objects/unset_004.phpt @@ -0,0 +1,70 @@ +--TEST-- +Lazy objects: unset of magic property may initialize object +--FILE-- +b = 2; + } + + public function __unset($name) { + var_dump($this->b); + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + unset($obj->a); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(1); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(1); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +int(2) +object(C)#%d (1) { + ["b"]=> + int(2) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +int(2) +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["b"]=> + int(2) + } +} diff --git a/Zend/tests/lazy_objects/unset_005.phpt b/Zend/tests/lazy_objects/unset_005.phpt new file mode 100644 index 0000000000000..11560dfed5032 --- /dev/null +++ b/Zend/tests/lazy_objects/unset_005.phpt @@ -0,0 +1,68 @@ +--TEST-- +Lazy objects: circular unset of magic property may initialize object +--FILE-- +b = 2; + } + + public function __unset($name) { + unset($this->a); + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + unset($obj->a); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(1); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(1); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +object(C)#%d (1) { + ["b"]=> + int(2) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["b"]=> + int(2) + } +} diff --git a/Zend/tests/lazy_objects/unset_006.phpt b/Zend/tests/lazy_objects/unset_006.phpt new file mode 100644 index 0000000000000..8f03b11026b55 --- /dev/null +++ b/Zend/tests/lazy_objects/unset_006.phpt @@ -0,0 +1,65 @@ +--TEST-- +Lazy objects: unset of undefined dynamic property initializes object +--FILE-- +b = 2; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + unset($obj->a); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(1); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(1); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +object(C)#%d (1) { + ["b"]=> + int(2) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["b"]=> + int(2) + } +} diff --git a/Zend/tests/lazy_objects/unset_007.phpt b/Zend/tests/lazy_objects/unset_007.phpt new file mode 100644 index 0000000000000..b7ca5adbfdfd4 --- /dev/null +++ b/Zend/tests/lazy_objects/unset_007.phpt @@ -0,0 +1,60 @@ +--TEST-- +Lazy objects: unset of undefined dynamic property initializes object (2) +--FILE-- +b = 2; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + // no var_dump($obj), so that properties ht is not initialized + var_dump('before unset'); + unset($obj->a); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(1); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(1); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +string(12) "before unset" +string(11) "initializer" +string(14) "C::__construct" +object(C)#%d (1) { + ["b"]=> + int(2) +} +# Virtual: +string(12) "before unset" +string(11) "initializer" +string(14) "C::__construct" +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["b"]=> + int(2) + } +} diff --git a/Zend/tests/lazy_objects/unset_008.phpt b/Zend/tests/lazy_objects/unset_008.phpt new file mode 100644 index 0000000000000..f8d110a963047 --- /dev/null +++ b/Zend/tests/lazy_objects/unset_008.phpt @@ -0,0 +1,60 @@ +--TEST-- +Lazy objects: unset of defined property does not initialize object +--FILE-- +a = 2; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + (new ReflectionProperty($obj, 'a'))->setRawValueWithoutLazyInitialization($obj, 1); + + var_dump($obj); + unset($obj->a); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(1); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(1); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +object(C)#%d (1) { + ["a"]=> + int(1) +} +object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} +# Virtual: +object(C)#%d (1) { + ["a"]=> + int(1) +} +object(C)#%d (0) { + ["a"]=> + uninitialized(int) +} diff --git a/Zend/tests/lazy_objects/unset_009.phpt b/Zend/tests/lazy_objects/unset_009.phpt new file mode 100644 index 0000000000000..3de9ca792ce1f --- /dev/null +++ b/Zend/tests/lazy_objects/unset_009.phpt @@ -0,0 +1,78 @@ +--TEST-- +Lazy objects: unset of undefined skipped property initializes object +--FILE-- +a = $a; + $this->b = 2; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + $reflector = new ReflectionClass($obj); + $reflector->getProperty('a')->skipLazyInitialization($obj); + $reflector->getProperty('b')->skipLazyInitialization($obj); + $reflector->getProperty('c')->skipLazyInitialization($obj); + + var_dump($obj); + unset($obj->a); + unset($obj->b); + unset($obj->c); + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(1); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(1); +}); + +test('Virtual', $obj); +--EXPECTF-- +# Ghost: +object(C)#%d (2) { + ["a"]=> + NULL + ["b"]=> + int(1) + ["c"]=> + uninitialized(int) +} +object(C)#%d (0) { + ["b"]=> + uninitialized(int) + ["c"]=> + uninitialized(int) +} +# Virtual: +object(C)#%d (2) { + ["a"]=> + NULL + ["b"]=> + int(1) + ["c"]=> + uninitialized(int) +} +object(C)#%d (0) { + ["b"]=> + uninitialized(int) + ["c"]=> + uninitialized(int) +} diff --git a/Zend/tests/lazy_objects/unset_010.phpt b/Zend/tests/lazy_objects/unset_010.phpt new file mode 100644 index 0000000000000..d22f3dcb83e92 --- /dev/null +++ b/Zend/tests/lazy_objects/unset_010.phpt @@ -0,0 +1,68 @@ +--TEST-- +Lazy objects: cannot unset hooked property +--FILE-- +a; } + set($value) { $this->a = $value; } + } + public int $b = 1; + + public function __construct(int $a) { + var_dump(__METHOD__); + $this->a = $a; + $this->b = 2; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + try { + unset($obj->a); + } catch (\Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(1); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(1); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +Error: Cannot unset hooked property C::$a +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +Error: Cannot unset hooked property C::$a +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} diff --git a/Zend/tests/lazy_objects/use_case_001.phpt b/Zend/tests/lazy_objects/use_case_001.phpt new file mode 100644 index 0000000000000..0bce225b1effe --- /dev/null +++ b/Zend/tests/lazy_objects/use_case_001.phpt @@ -0,0 +1,44 @@ +--TEST-- +Lazy objects: Lazy service initialization in dependency injection container +--FILE-- +newInstanceWithoutConstructor(); + (new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + $obj->__construct(); + }); + return $obj; + } + + public function getApplicationService(): Application { + return new Application($this->getEntityManagerService()); + } +} + +$container = new Container(); + +printf("Service can be fetched without initializing dependencies\n"); +$application = $container->getApplicationService(); +--EXPECTF-- +Service can be fetched without initializing dependencies +string(24) "Application::__construct" diff --git a/Zend/tests/lazy_objects/use_case_001b.phpt b/Zend/tests/lazy_objects/use_case_001b.phpt new file mode 100644 index 0000000000000..e32527bca1d78 --- /dev/null +++ b/Zend/tests/lazy_objects/use_case_001b.phpt @@ -0,0 +1,44 @@ +--TEST-- +Lazy objects: Lazy service initialization in dependency injection container via factory +--FILE-- +newInstanceWithoutConstructor(); + (new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + return new EntityManager(); + }); + return $obj; + } + + public function getApplicationService(): Application { + return new Application($this->getEntityManagerService()); + } +} + +$container = new Container(); + +printf("Service can be fetched without initializing dependencies\n"); +$application = $container->getApplicationService(); +--EXPECTF-- +Service can be fetched without initializing dependencies +string(24) "Application::__construct" diff --git a/Zend/tests/lazy_objects/use_case_002.phpt b/Zend/tests/lazy_objects/use_case_002.phpt new file mode 100644 index 0000000000000..0bbead439c1f7 --- /dev/null +++ b/Zend/tests/lazy_objects/use_case_002.phpt @@ -0,0 +1,52 @@ +--TEST-- +Lazy objects: Lazy entity loading +--FILE-- +id; + } + + public function getName(): string { + return $this->name; + } +} + +class EntityManager { + public function lazyLoad(string $fqcn, int $id): object { + $entity = (new ReflectionClass($fqcn))->newInstanceWithoutConstructor(); + (new ReflectionClass($entity))->resetAsLazyGhost($entity, function ($obj) { + var_dump('initializer'); + $prop = new ReflectionProperty($obj, 'name'); + $prop->setValue($obj, 'John Doe'); + }); + + (new ReflectionProperty($entity, 'id'))->setRawValueWithoutLazyInitialization($entity, $id); + + return $entity; + } +} + +$em = new EntityManager(); +$user = $em->lazyLoad(User::class, 123); + +printf("Fetching identifier does not trigger initializer\n"); +var_dump($user->getId()); + +printf("Fetching anything else triggers initializer\n"); +var_dump($user->getName()); +--EXPECTF-- +Fetching identifier does not trigger initializer +int(123) +Fetching anything else triggers initializer +string(11) "initializer" +string(8) "John Doe" diff --git a/Zend/tests/lazy_objects/write_001.phpt b/Zend/tests/lazy_objects/write_001.phpt new file mode 100644 index 0000000000000..d5c4cb8fe01b6 --- /dev/null +++ b/Zend/tests/lazy_objects/write_001.phpt @@ -0,0 +1,69 @@ +--TEST-- +Lazy objects: property write initializes object +--FILE-- +b = 3; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + $obj->a = 2; + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +object(C)#%d (2) { + ["a"]=> + int(2) + ["b"]=> + int(3) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["a"]=> + int(2) + ["b"]=> + int(3) + } +} diff --git a/Zend/tests/lazy_objects/write_002.phpt b/Zend/tests/lazy_objects/write_002.phpt new file mode 100644 index 0000000000000..34f76f087d892 --- /dev/null +++ b/Zend/tests/lazy_objects/write_002.phpt @@ -0,0 +1,74 @@ +--TEST-- +Lazy objects: property write to custom property initializes object +--FILE-- +a = 1; + $this->b = 2; + } +} +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + $obj->custom = 3; + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +object(C)#%d (3) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["custom"]=> + int(3) +} +# Virtual: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (3) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["custom"]=> + int(3) + } +} diff --git a/Zend/tests/lazy_objects/write_003.phpt b/Zend/tests/lazy_objects/write_003.phpt new file mode 100644 index 0000000000000..288b8125820f6 --- /dev/null +++ b/Zend/tests/lazy_objects/write_003.phpt @@ -0,0 +1,64 @@ +--TEST-- +Lazy objects: property write to magic property initializes object +--FILE-- +a = 1; + } + + public function __set($name, $value) { + $this->a = $value; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + $obj->magic = 3; + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { +} +string(11) "initializer" +string(14) "C::__construct" +object(C)#%d (1) { + ["a"]=> + int(3) +} +# Virtual: +lazy proxy object(C)#%d (0) { +} +string(11) "initializer" +string(14) "C::__construct" +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["a"]=> + int(3) + } +} diff --git a/Zend/tests/lazy_objects/write_004.phpt b/Zend/tests/lazy_objects/write_004.phpt new file mode 100644 index 0000000000000..6ea60ad2d04e2 --- /dev/null +++ b/Zend/tests/lazy_objects/write_004.phpt @@ -0,0 +1,64 @@ +--TEST-- +Lazy objects: circular property write to magic property initializes object +--FILE-- +a = 1; + } + + public function __set($name, $value) { + $this->a = $value; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + $obj->a = 3; + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { +} +string(11) "initializer" +string(14) "C::__construct" +object(C)#%d (1) { + ["a"]=> + int(3) +} +# Virtual: +lazy proxy object(C)#%d (0) { +} +string(11) "initializer" +string(14) "C::__construct" +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["a"]=> + int(3) + } +} diff --git a/Zend/tests/lazy_objects/write_005.phpt b/Zend/tests/lazy_objects/write_005.phpt new file mode 100644 index 0000000000000..6aafc032d55fc --- /dev/null +++ b/Zend/tests/lazy_objects/write_005.phpt @@ -0,0 +1,48 @@ +--TEST-- +Lazy objects: property write with initializer exception +--FILE-- +a = 1; + } catch (Exception $e) { + printf("%s\n", $e->getMessage()); + } + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + throw new \Exception('init exception'); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + throw new \Exception('init exception'); +}); + +test('Ghost', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { +} +init exception +lazy ghost object(C)#%d (0) { +} +# Ghost: +lazy proxy object(C)#%d (0) { +} +init exception +lazy proxy object(C)#%d (0) { +} diff --git a/Zend/tests/lazy_objects/write_006.phpt b/Zend/tests/lazy_objects/write_006.phpt new file mode 100644 index 0000000000000..70b1b0c33b712 --- /dev/null +++ b/Zend/tests/lazy_objects/write_006.phpt @@ -0,0 +1,81 @@ +--TEST-- +Lazy objects: write to skipped property does not initialize object +--FILE-- +getProperty('a')->skipLazyInitialization($obj); + $reflector->getProperty('b')->skipLazyInitialization($obj); + $reflector->getProperty('c')->skipLazyInitialization($obj); + + var_dump($obj); + $obj->a = 2; + $obj->b = 2; + $obj->c = 2; + var_dump($obj); +} + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); +(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Virtual', $obj); + +--EXPECTF-- +# Ghost: +object(C)#%d (2) { + ["a"]=> + NULL + ["b"]=> + int(1) + ["c"]=> + uninitialized(int) +} +object(C)#%d (3) { + ["a"]=> + int(2) + ["b"]=> + int(2) + ["c"]=> + int(2) +} +# Virtual: +object(C)#%d (2) { + ["a"]=> + NULL + ["b"]=> + int(1) + ["c"]=> + uninitialized(int) +} +object(C)#%d (3) { + ["a"]=> + int(2) + ["b"]=> + int(2) + ["c"]=> + int(2) +} diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 377bc23c46bd2..9b797880684f1 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -885,7 +885,7 @@ ZEND_FUNCTION(get_mangled_object_vars) Z_PARAM_OBJ(obj) ZEND_PARSE_PARAMETERS_END(); - properties = obj->handlers->get_properties(obj); + properties = zend_get_properties_no_init(obj); if (!properties) { ZVAL_EMPTY_ARRAY(return_value); return; diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index f1f5bfc84516f..21e17fe8c666b 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -171,6 +171,7 @@ void init_executor(void) /* {{{ */ zend_stack_init(&EG(user_exception_handlers), sizeof(zval)); zend_objects_store_init(&EG(objects_store), 1024); + zend_lazy_objects_init(&EG(lazy_objects_store)); EG(full_tables_cleanup) = 0; ZEND_ATOMIC_BOOL_INIT(&EG(vm_interrupt), false); @@ -492,6 +493,7 @@ void shutdown_executor(void) /* {{{ */ zend_stack_destroy(&EG(user_error_handlers_error_reporting)); zend_stack_destroy(&EG(user_error_handlers)); zend_stack_destroy(&EG(user_exception_handlers)); + zend_lazy_objects_destroy(&EG(lazy_objects_store)); zend_objects_store_destroy(&EG(objects_store)); if (EG(in_autoload)) { zend_hash_destroy(EG(in_autoload)); diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 3aa967b8dd6bb..539793c8325a6 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -42,6 +42,7 @@ #include "zend_call_stack.h" #include "zend_max_execution_timer.h" #include "zend_strtod.h" +#include "zend_lazy_objects.h" /* Define ZTS if you want a thread-safe Zend */ /*#undef ZTS*/ @@ -246,6 +247,7 @@ struct _zend_executor_globals { zend_ini_entry *error_reporting_ini_entry; zend_objects_store objects_store; + zend_lazy_objects_store lazy_objects_store; zend_object *exception, *prev_exception; const zend_op *opline_before_exception; zend_op exception_op[3]; diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c new file mode 100644 index 0000000000000..3e2740a08ed07 --- /dev/null +++ b/Zend/zend_lazy_objects.c @@ -0,0 +1,668 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Arnaud Le Blanc | + +----------------------------------------------------------------------+ +*/ + +/* Lazy objects are standard zend_object whose initialization is defered until + * one of their properties backing store is accessed for the first time. + * + * This is implemented by using the same fallback mechanism as __get and __set + * magic methods that is triggered when an undefined property is accessed. + * + * Execution of methods or virtual property hooks do not trigger initialization. + * + * A lazy object can be created via the Reflection API. The user specifies an + * initializer function that is called when initialization is required. + * + * There are two kinds of lazy objects: + * + * - Ghosts: These are initialized in-place by the initializer function + * - Proxy: The initializer returns a new instance. After initialization, + * interaction with the proxy object are proxied to the instance. + * + * Internal objects are not supported. + */ + +#include "zend_API.h" +#include "zend_compile.h" +#include "zend_execute.h" +#include "zend_hash.h" +#include "zend_object_handlers.h" +#include "zend_objects_API.h" +#include "zend_operators.h" +#include "zend_types.h" +#include "zend_variables.h" +#include "zend_lazy_objects.h" + +/** + * Information about each lazy object is stored outside of zend_objects, in + * EG(lazy_objects_store). For ghost objects, we can release this after the + * object is initialized. + */ +typedef struct _zend_lazy_object_info { + union { + struct { + zend_fcall_info_cache fcc; + zval zv; /* ReflectionClass::getLazyInitializer() */ + } initializer; + zend_object *instance; /* For initialized lazy proxy objects */ + } u; + zend_lazy_object_flags_t flags; + int lazy_properties_count; +} zend_lazy_object_info; + +/* zend_hash dtor_func_t for zend_lazy_objects_store.infos */ +static void zend_lazy_object_info_dtor_func(zval *pElement) +{ + zend_lazy_object_info *info = (zend_lazy_object_info*) Z_PTR_P(pElement); + + if (info->flags & ZEND_LAZY_OBJECT_INITIALIZED) { + ZEND_ASSERT(info->flags & ZEND_LAZY_OBJECT_STRATEGY_PROXY); + zend_object_release(info->u.instance); + } else { + zval_ptr_dtor(&info->u.initializer.zv); + zend_fcc_dtor(&info->u.initializer.fcc); + } + + efree(info); +} + +void zend_lazy_objects_init(zend_lazy_objects_store *store) +{ + zend_hash_init(&store->infos, 8, NULL, zend_lazy_object_info_dtor_func, false); +} + +void zend_lazy_objects_destroy(zend_lazy_objects_store *store) +{ + ZEND_ASSERT(zend_hash_num_elements(&store->infos) == 0 || CG(unclean_shutdown)); + zend_hash_destroy(&store->infos); +} + +void zend_lazy_object_set_info(zend_object *obj, zend_lazy_object_info *info) +{ + ZEND_ASSERT(OBJ_EXTRA_FLAGS(obj) & (IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY)); + + zval *zv = zend_hash_index_add_new_ptr(&EG(lazy_objects_store).infos, obj->handle, info); + ZEND_ASSERT(zv); +} + +zend_lazy_object_info* zend_lazy_object_get_info(zend_object *obj) +{ + ZEND_ASSERT(OBJ_EXTRA_FLAGS(obj) & (IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY)); + + zend_lazy_object_info *info = zend_hash_index_find_ptr(&EG(lazy_objects_store).infos, obj->handle); + ZEND_ASSERT(info); + + return info; +} + +zval* zend_lazy_object_get_initializer_zv(zend_object *obj) +{ + ZEND_ASSERT(!zend_lazy_object_initialized(obj)); + + zend_lazy_object_info *info = zend_lazy_object_get_info(obj); + + ZEND_ASSERT(!(info->flags & ZEND_LAZY_OBJECT_INITIALIZED)); + + return &info->u.initializer.zv; +} + +zend_fcall_info_cache* zend_lazy_object_get_initializer_fcc(zend_object *obj) +{ + ZEND_ASSERT(!zend_lazy_object_initialized(obj)); + + zend_lazy_object_info *info = zend_lazy_object_get_info(obj); + + ZEND_ASSERT(!(info->flags & ZEND_LAZY_OBJECT_INITIALIZED)); + + return &info->u.initializer.fcc; +} + +zend_object* zend_lazy_object_get_instance(zend_object *obj) +{ + ZEND_ASSERT(zend_lazy_object_initialized(obj)); + + if (zend_object_is_lazy_proxy(obj)) { + zend_lazy_object_info *info = zend_lazy_object_get_info(obj); + + ZEND_ASSERT(info->flags & ZEND_LAZY_OBJECT_INITIALIZED); + + return info->u.instance; + } + + return obj; +} + +zend_lazy_object_flags_t zend_lazy_object_get_flags(zend_object *obj) +{ + return zend_lazy_object_get_info(obj)->flags; +} + +void zend_lazy_object_del_info(zend_object *obj) +{ + zend_result res = zend_hash_index_del(&EG(lazy_objects_store).infos, obj->handle); + ZEND_ASSERT(res == SUCCESS); +} + +bool zend_lazy_object_decr_lazy_props(zend_object *obj) +{ + ZEND_ASSERT(zend_object_is_lazy(obj)); + ZEND_ASSERT(!zend_lazy_object_initialized(obj)); + + zend_lazy_object_info *info = zend_lazy_object_get_info(obj); + + ZEND_ASSERT(info->lazy_properties_count > 0); + + info->lazy_properties_count--; + + return info->lazy_properties_count == 0; +} + +/** + * Making objects lazy + */ + +/* Make object 'obj' lazy. If 'obj' is NULL, create a lazy instance of + * class 'class_type' */ +ZEND_API zend_object *zend_object_make_lazy(zend_object *obj, + zend_class_entry *ce, zval *initializer_zv, + zend_fcall_info_cache *initializer_fcc, zend_lazy_object_flags_t flags) +{ + ZEND_ASSERT(!(flags & ~(ZEND_LAZY_OBJECT_USER_FLAGS|ZEND_LAZY_OBJECT_STRATEGY_FLAGS))); + ZEND_ASSERT((flags & ZEND_LAZY_OBJECT_STRATEGY_FLAGS) == ZEND_LAZY_OBJECT_STRATEGY_GHOST + || (flags & ZEND_LAZY_OBJECT_STRATEGY_FLAGS) == ZEND_LAZY_OBJECT_STRATEGY_PROXY); + + ZEND_ASSERT(!obj || (!zend_object_is_lazy(obj) || zend_lazy_object_initialized(obj))); + ZEND_ASSERT(!obj || instanceof_function(obj->ce, ce)); + + /* Internal classes are not supported */ + if (UNEXPECTED(ce->type == ZEND_INTERNAL_CLASS && ce != zend_standard_class_def)) { + zend_throw_error(NULL, "Cannot make instance of internal class lazy: %s is internal", ZSTR_VAL(ce->name)); + return NULL; + } + + for (zend_class_entry *parent = ce->parent; parent; parent = parent->parent) { + if (UNEXPECTED(parent->type == ZEND_INTERNAL_CLASS && parent != zend_standard_class_def)) { + zend_throw_error(NULL, "Cannot make instance of internal class lazy: %s inherits internal class %s", + ZSTR_VAL(ce->name), ZSTR_VAL(parent->name)); + return NULL; + } + } + + int lazy_properties_count = 0; + + if (!obj) { + zval zobj; + if (UNEXPECTED(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS|ZEND_ACC_ENUM))) { + /* Slow path: use object_init_ex() */ + if (object_init_ex(&zobj, ce) == FAILURE) { + ZEND_ASSERT(EG(exception)); + return NULL; + } + obj = Z_OBJ(zobj); + } else { + obj = zend_objects_new(ce); + } + + for (int i = 0; i < obj->ce->default_properties_count; i++) { + zval *p = &obj->properties_table[i]; + ZVAL_UNDEF(p); + if (EXPECTED(obj->ce->properties_info_table[i])) { + Z_PROP_FLAG_P(p) = IS_PROP_UNINIT | IS_PROP_LAZY; + lazy_properties_count++; + } else { + Z_PROP_FLAG_P(p) = 0; + } + } + } else { + if (zend_object_is_lazy(obj)) { + ZEND_ASSERT(zend_object_is_lazy_proxy(obj) && zend_lazy_object_initialized(obj)); + OBJ_EXTRA_FLAGS(obj) &= ~(IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY); + zend_lazy_object_del_info(obj); + } else if (!(flags & ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR) + && !(OBJ_FLAGS(obj) & IS_OBJ_DESTRUCTOR_CALLED)) { + if (obj->handlers->dtor_obj != zend_objects_destroy_object + || obj->ce->destructor) { + GC_ADD_FLAGS(obj, IS_OBJ_DESTRUCTOR_CALLED); + GC_ADDREF(obj); + obj->handlers->dtor_obj(obj); + GC_DELREF(obj); + if (EG(exception)) { + return NULL; + } + } + } + + GC_DEL_FLAGS(obj, IS_OBJ_DESTRUCTOR_CALLED); + + /* unset() dynamic properties */ + zend_object_dtor_dynamic_properties(obj); + obj->properties = NULL; + + /* unset() declared properties */ + for (int i = 0; i < ce->default_properties_count; i++) { + zend_property_info *prop_info = obj->ce->properties_info_table[i]; + if (EXPECTED(prop_info)) { + zval *p = &obj->properties_table[i]; + if (Z_TYPE_P(p) != IS_UNDEF) { + if ((prop_info->flags & ZEND_ACC_READONLY) && !(Z_PROP_FLAG_P(p) & IS_PROP_REINITABLE) + && (obj->ce->ce_flags & ZEND_ACC_FINAL)) { + continue; + } + zend_object_dtor_property(obj, p); + ZVAL_UNDEF(p); + } + Z_PROP_FLAG_P(p) = IS_PROP_UNINIT | IS_PROP_LAZY; + lazy_properties_count++; + } + } + } + + /* Objects become non-lazy if all properties are made non-lazy before + * initialization is triggerd. If the object has no properties to begin + * with, this happens immediately. */ + if (UNEXPECTED(!lazy_properties_count)) { + return obj; + } + + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY; + + if (flags & ZEND_LAZY_OBJECT_STRATEGY_PROXY) { + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_PROXY; + } else { + ZEND_ASSERT(flags & ZEND_LAZY_OBJECT_STRATEGY_GHOST); + } + + zend_lazy_object_info *info = emalloc(sizeof(*info)); + zend_fcc_dup(&info->u.initializer.fcc, initializer_fcc); + ZVAL_COPY(&info->u.initializer.zv, initializer_zv); + info->flags = flags; + info->lazy_properties_count = lazy_properties_count; + zend_lazy_object_set_info(obj, info); + + return obj; +} + +/** + * Initialization of lazy objects + */ + +/* Mark object as initialized. Lazy properties are initialized to their default + * value and the initializer is not called. */ +ZEND_API zend_object *zend_lazy_object_mark_as_initialized(zend_object *obj) +{ + ZEND_ASSERT(zend_object_is_lazy(obj)); + ZEND_ASSERT(!zend_lazy_object_initialized(obj)); + + zend_class_entry *ce = obj->ce; + + if (UNEXPECTED(!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED))) { + if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) { + ZEND_ASSERT(EG(exception)); + return NULL; + } + } + + zval *default_properties_table = CE_DEFAULT_PROPERTIES_TABLE(ce); + zval *properties_table = obj->properties_table; + + OBJ_EXTRA_FLAGS(obj) &= ~(IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY); + + for (int i = 0; i < ce->default_properties_count; i++) { + if (Z_PROP_FLAG_P(&properties_table[i]) & IS_PROP_LAZY) { + ZVAL_COPY_PROP(&properties_table[i], &default_properties_table[i]); + } + } + + zend_lazy_object_del_info(obj); + + return obj; +} + +/* Revert initializer effects */ +static void zend_lazy_object_revert_init(zend_object *obj, zval *properties_table_snapshot, HashTable *properties_snapshot) +{ + zend_class_entry *ce = obj->ce; + + if (ce->default_properties_count) { + ZEND_ASSERT(properties_table_snapshot); + zval *properties_table = obj->properties_table; + + for (int i = 0; i < ce->default_properties_count; i++) { + zval *p = &properties_table[i]; + zend_object_dtor_property(obj, p); + ZVAL_COPY_PROP(p, &properties_table_snapshot[i]); + Z_TRY_DELREF_P(p); + + zend_property_info *prop_info = ce->properties_info_table[i]; + if (Z_ISREF_P(p) && prop_info && ZEND_TYPE_IS_SET(prop_info->type)) { + ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(p), prop_info); + } + } + + efree(properties_table_snapshot); + } + if (properties_snapshot) { + if (obj->properties != properties_snapshot) { + ZEND_ASSERT((GC_FLAGS(properties_snapshot) & IS_ARRAY_IMMUTABLE) || GC_REFCOUNT(properties_snapshot) >= 1); + zend_release_properties(obj->properties); + obj->properties = properties_snapshot; + } else { + ZEND_ASSERT((GC_FLAGS(properties_snapshot) & IS_ARRAY_IMMUTABLE) || GC_REFCOUNT(properties_snapshot) > 1); + zend_release_properties(properties_snapshot); + } + } else if (obj->properties) { + zend_release_properties(obj->properties); + obj->properties = NULL; + } + + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY; +} + +static bool zend_lazy_object_compatible(zend_object *real_object, zend_object *lazy_object) +{ + if (EXPECTED(real_object->ce == lazy_object->ce)) { + return true; + } + + if (!instanceof_function(lazy_object->ce, real_object->ce)) { + return false; + } + + /* zend_hash_num_elements(ce.properties_info) reports the actual number of + * properties. ce.default_properties_count is off by the number of property + * overrides. */ + if (zend_hash_num_elements(&lazy_object->ce->properties_info) != zend_hash_num_elements(&real_object->ce->properties_info)) { + return false; + } + + return lazy_object->ce->destructor == real_object->ce->destructor + && lazy_object->ce->clone == real_object->ce->clone; +} + +/* Initialize a lazy proxy object */ +static zend_object *zend_lazy_object_init_proxy(zend_object *obj) +{ + ZEND_ASSERT(zend_object_is_lazy_proxy(obj)); + ZEND_ASSERT(!zend_lazy_object_initialized(obj)); + + zend_lazy_object_info *info = zend_lazy_object_get_info(obj); + + /* prevent reentrant initialization */ + OBJ_EXTRA_FLAGS(obj) &= ~(IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY); + + /* Call factory */ + zval retval; + int argc = 1; + zval zobj; + HashTable *named_params = NULL; + zend_fcall_info_cache *initializer = &info->u.initializer.fcc; + + ZVAL_OBJ(&zobj, obj); + + zend_call_known_fcc(initializer, &retval, argc, &zobj, named_params); + + if (UNEXPECTED(EG(exception))) { + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY; + return NULL; + } + + if (UNEXPECTED(Z_TYPE(retval) != IS_OBJECT || !zend_lazy_object_compatible(Z_OBJ(retval), obj))) { + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY; + zend_type_error("The real instance class %s is not compatible with the proxy class %s. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor or __clone methods.", + zend_zval_value_name(&retval), + ZSTR_VAL(obj->ce->name)); + zval_ptr_dtor(&retval); + return NULL; + } + + if (UNEXPECTED(Z_OBJ(retval) == obj || zend_object_is_lazy(Z_OBJ(retval)))) { + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY; + zend_throw_error(NULL, "Lazy proxy factory must return a non-lazy object"); + zval_ptr_dtor(&retval); + return NULL; + } + + if (info->flags & ZEND_LAZY_OBJECT_CLONE) { + /* For uninitialized lazy proxies, cloning of the real instance is + * postponed until initialization */ + + zend_object *clone = Z_OBJ_HT(retval)->clone_obj(Z_OBJ(retval)); + if (EG(exception)) { + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY; + zval_ptr_dtor(&retval); + OBJ_RELEASE(clone); + return NULL; + } + + ZEND_ASSERT(zend_lazy_object_compatible(clone, obj)); + + if (zend_object_is_lazy(clone)) { + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY; + zend_throw_error(NULL, "Lazy proxy factory must return a non-lazy object"); + zval_ptr_dtor(&retval); + return NULL; + } + + zval_ptr_dtor(&retval); + ZVAL_OBJ(&retval, clone); + } + + zend_fcc_dtor(&info->u.initializer.fcc); + zval_ptr_dtor(&info->u.initializer.zv); + info->u.instance = Z_OBJ(retval); + info->flags |= ZEND_LAZY_OBJECT_INITIALIZED; + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_PROXY; + + /* unset() properties of the proxy. This ensures that all accesses are be + * delegated to the backing instance from now on. */ + // TODO: test that props are undef after initialization + zend_object_dtor_dynamic_properties(obj); + obj->properties = NULL; + + for (int i = 0; i < Z_OBJ(retval)->ce->default_properties_count; i++) { + if (EXPECTED(Z_OBJ(retval)->ce->properties_info_table[i])) { + zend_object_dtor_property(obj, &obj->properties_table[i]); + ZVAL_UNDEF(&obj->properties_table[i]); + Z_PROP_FLAG_P(&obj->properties_table[i]) = IS_PROP_UNINIT | IS_PROP_LAZY; + } + } + + return Z_OBJ(retval); +} + +/* Initialize a lazy object. */ +ZEND_API zend_object *zend_lazy_object_init(zend_object *obj) +{ + ZEND_ASSERT(zend_object_is_lazy(obj)); + + /* If obj is an initialized lazy proxy, return the real instance. This + * supports the following pattern: + * if (zend_lazy_object_must_init(obj)) { + * instance = zend_lazy_object_init(obj); + * } + */ + if (zend_lazy_object_initialized(obj)) { + ZEND_ASSERT(zend_object_is_lazy_proxy(obj)); + zend_lazy_object_info *info = zend_lazy_object_get_info(obj); + ZEND_ASSERT(info->flags & ZEND_LAZY_OBJECT_INITIALIZED); + return info->u.instance; + } + + zend_class_entry *ce = obj->ce; + + if (UNEXPECTED(!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED))) { + if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) { + ZEND_ASSERT(EG(exception)); + return NULL; + } + } + + if (zend_object_is_lazy_proxy(obj)) { + return zend_lazy_object_init_proxy(obj); + } + + zend_fcall_info_cache *initializer = zend_lazy_object_get_initializer_fcc(obj); + + /* Prevent reentrant initialization */ + OBJ_EXTRA_FLAGS(obj) &= ~IS_OBJ_LAZY; + + /* Snapshot dynamic properties */ + HashTable *properties_snapshot = obj->properties; + if (properties_snapshot) { + GC_TRY_ADDREF(properties_snapshot); + } + + zval *properties_table_snapshot = NULL; + + /* Snapshot declared properties and initialize lazy properties to their + * default value */ + if (ce->default_properties_count) { + zval *default_properties_table = CE_DEFAULT_PROPERTIES_TABLE(ce); + zval *properties_table = obj->properties_table; + properties_table_snapshot = emalloc(sizeof(*properties_table_snapshot) * ce->default_properties_count); + + for (int i = 0; i < ce->default_properties_count; i++) { + ZVAL_COPY_PROP(&properties_table_snapshot[i], &properties_table[i]); + if (Z_PROP_FLAG_P(&properties_table[i]) & IS_PROP_LAZY) { + ZVAL_COPY_PROP(&properties_table[i], &default_properties_table[i]); + } + } + } + + /* Call initializer */ + zval retval; + int argc = 1; + zval zobj; + HashTable *named_params = NULL; + + ZVAL_OBJ(&zobj, obj); + + zend_call_known_fcc(initializer, &retval, argc, &zobj, named_params); + + if (EG(exception)) { + zend_lazy_object_revert_init(obj, properties_table_snapshot, properties_snapshot); + return NULL; + } + + if (Z_TYPE(retval) != IS_NULL) { + zend_lazy_object_revert_init(obj, properties_table_snapshot, properties_snapshot); + zval_ptr_dtor(&retval); + zend_type_error("Lazy object initializer must return NULL or no value"); + return NULL; + } + + if (properties_table_snapshot) { + for (int i = 0; i < obj->ce->default_properties_count; i++) { + zval *p = &properties_table_snapshot[i]; + /* Use zval_ptr_dtor directly here (not zend_object_dtor_property), + * as any reference type_source will have already been deleted in + * case the prop is not bound to this value anymore. */ + i_zval_ptr_dtor(p); + } + efree(properties_table_snapshot); + } + + if (properties_snapshot) { + zend_release_properties(properties_snapshot); + } + + zend_lazy_object_del_info(obj); + + return obj; +} + +/* Mark an object as non-lazy (after all properties were initialized) */ +void zend_lazy_object_realize(zend_object *obj) +{ + ZEND_ASSERT(zend_object_is_lazy(obj)); + ZEND_ASSERT(!zend_lazy_object_initialized(obj)); + + zend_lazy_object_del_info(obj); + +#if ZEND_DEBUG + for (int i = 0; i < obj->ce->default_properties_count; i++) { + ZEND_ASSERT(!(Z_PROP_FLAG_P(&obj->properties_table[i]) & IS_PROP_LAZY)); + } +#endif + + OBJ_EXTRA_FLAGS(obj) &= ~(IS_OBJ_LAZY | IS_OBJ_LAZY_PROXY); +} + +/* Initialize object and clone it. For proxies, we clone both the proxy and its + * real instance, and we don't call __clone() on the proxy. */ +zend_object *zend_lazy_object_clone(zend_object *old_obj) +{ + ZEND_ASSERT(zend_object_is_lazy(old_obj)); + + if (UNEXPECTED(!zend_lazy_object_initialized(old_obj) && !zend_lazy_object_init(old_obj))) { + ZEND_ASSERT(EG(exception)); + /* Clone handler must always return an object. It is discarded later due + * to the exception. */ + zval zv; + object_init_ex(&zv, old_obj->ce); + GC_ADD_FLAGS(Z_OBJ(zv), IS_OBJ_DESTRUCTOR_CALLED); + return Z_OBJ(zv); + } + + if (!zend_object_is_lazy_proxy(old_obj)) { + return zend_objects_clone_obj(old_obj); + } + + zend_lazy_object_info *info = zend_lazy_object_get_info(old_obj); + zend_class_entry *ce = old_obj->ce; + zend_object *new_proxy = zend_objects_new(ce); + + for (int i = 0; i < ce->default_properties_count; i++) { + zval *p = &new_proxy->properties_table[i]; + ZVAL_UNDEF(p); + if (EXPECTED(ce->properties_info_table[i])) { + Z_PROP_FLAG_P(p) = IS_PROP_UNINIT | IS_PROP_LAZY; + } else { + Z_PROP_FLAG_P(p) = 0; + } + } + + OBJ_EXTRA_FLAGS(new_proxy) = OBJ_EXTRA_FLAGS(old_obj); + + zend_lazy_object_info *new_info = emalloc(sizeof(*info)); + *new_info = *info; + new_info->u.instance = zend_objects_clone_obj(info->u.instance); + + zend_lazy_object_set_info(new_proxy, new_info); + + return new_proxy; +} + +HashTable *zend_lazy_object_debug_info(zend_object *object, int *is_temp) +{ + ZEND_ASSERT(zend_object_is_lazy(object)); + + if (zend_object_is_lazy_proxy(object)) { + if (zend_lazy_object_initialized(object)) { + HashTable *properties = zend_new_array(0); + zval instance; + ZVAL_OBJ(&instance, zend_lazy_object_get_instance(object)); + Z_ADDREF(instance); + zend_hash_str_add(properties, "instance", strlen("instance"), &instance); + *is_temp = 1; + return properties; + } + } + + *is_temp = 0; + return zend_get_properties_no_init(object); +} diff --git a/Zend/zend_lazy_objects.h b/Zend/zend_lazy_objects.h new file mode 100644 index 0000000000000..ca1ad4a630a3d --- /dev/null +++ b/Zend/zend_lazy_objects.h @@ -0,0 +1,107 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Arnaud Le Blanc | + +----------------------------------------------------------------------+ +*/ + +#ifndef ZEND_LAZY_OBJECT_H +#define ZEND_LAZY_OBJECT_H + +#include "Zend/zend_types.h" + +/* Lazy object is a lazy proxy object */ +#define ZEND_LAZY_OBJECT_STRATEGY_PROXY (1<<0) + +/* Lazy object is a lazy ghost object */ +#define ZEND_LAZY_OBJECT_STRATEGY_GHOST (1<<1) + +/* Lazy object is initialized (info.u is an instance) */ +#define ZEND_LAZY_OBJECT_INITIALIZED (1<<2) + +/* Serialization skips initialization */ +#define ZEND_LAZY_OBJECT_SKIP_INITIALIZATION_ON_SERIALIZE (1<<3) + +/* Do not call destructor when making existing object lazy */ +#define ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR (1<<4) + +/* The object is a clone */ +#define ZEND_LAZY_OBJECT_CLONE (1<<5) + +#define ZEND_LAZY_OBJECT_USER_FLAGS ( \ + ZEND_LAZY_OBJECT_SKIP_INITIALIZATION_ON_SERIALIZE | \ + ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR \ +) + +#define ZEND_LAZY_OBJECT_STRATEGY_FLAGS ( \ + ZEND_LAZY_OBJECT_STRATEGY_PROXY | \ + ZEND_LAZY_OBJECT_STRATEGY_GHOST \ +) + +typedef uint8_t zend_lazy_object_flags_t; + +typedef struct _zend_lazy_objects_store { + /* object handle -> *zend_lazy_object_info */ + HashTable infos; +} zend_lazy_objects_store; + +typedef struct _zend_fcall_info zend_fcall_info; +typedef struct _zend_fcall_info_cache zend_fcall_info_cache; + +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_mark_as_initialized(zend_object *obj); + +void zend_lazy_objects_init(zend_lazy_objects_store *store); +void zend_lazy_objects_destroy(zend_lazy_objects_store *store); +zval* zend_lazy_object_get_initializer_zv(zend_object *obj); +zend_fcall_info_cache* zend_lazy_object_get_initializer_fcc(zend_object *obj); +zend_object *zend_lazy_object_get_instance(zend_object *obj); +zend_lazy_object_flags_t zend_lazy_object_get_flags(zend_object *obj); +void zend_lazy_object_del_info(zend_object *obj); +zend_object *zend_lazy_object_clone(zend_object *old_obj); +HashTable *zend_lazy_object_debug_info(zend_object *object, int *is_temp); +bool zend_lazy_object_decr_lazy_props(zend_object *obj); +void zend_lazy_object_realize(zend_object *obj); + +static zend_always_inline bool zend_object_is_lazy(zend_object *obj) +{ + return (OBJ_EXTRA_FLAGS(obj) & (IS_OBJ_LAZY | IS_OBJ_LAZY_PROXY)); +} + +static zend_always_inline bool zend_object_is_lazy_proxy(zend_object *obj) +{ + return (OBJ_EXTRA_FLAGS(obj) & IS_OBJ_LAZY_PROXY); +} + +static zend_always_inline bool zend_lazy_object_initialized(zend_object *obj) +{ + return !(OBJ_EXTRA_FLAGS(obj) & IS_OBJ_LAZY); +} + +/* True if accessing a lazy prop on obj mandates a call to + * zend_lazy_object_init() */ +static zend_always_inline bool zend_lazy_object_must_init(zend_object *obj) +{ + return zend_object_is_lazy(obj); +} + +static inline bool zend_lazy_object_initialize_on_serialize(zend_object *obj) +{ + return !(zend_lazy_object_get_flags(obj) & ZEND_LAZY_OBJECT_SKIP_INITIALIZATION_ON_SERIALIZE); +} + +#endif /* ZEND_LAZY_OBJECT_H */ diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index fdac24ccb258b..cceede535cb8d 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -20,6 +20,7 @@ #include "zend.h" #include "zend_globals.h" +#include "zend_lazy_objects.h" #include "zend_variables.h" #include "zend_API.h" #include "zend_objects.h" @@ -92,6 +93,7 @@ ZEND_API HashTable *rebuild_object_properties_internal(zend_object *zobj) /* {{{ } /* }}} */ +/* Implements the fast path for array cast */ ZEND_API HashTable *zend_std_build_object_properties_array(zend_object *zobj) /* {{{ */ { zend_property_info *prop_info; @@ -100,6 +102,7 @@ ZEND_API HashTable *zend_std_build_object_properties_array(zend_object *zobj) /* zval* prop; int i; + ZEND_ASSERT(!(zend_object_is_lazy_proxy(zobj) && zend_lazy_object_initialized(zobj))); ZEND_ASSERT(!zobj->properties); ht = zend_new_array(ce->default_properties_count); if (ce->default_properties_count) { @@ -130,13 +133,29 @@ ZEND_API HashTable *zend_std_build_object_properties_array(zend_object *zobj) /* ZEND_API HashTable *zend_std_get_properties(zend_object *zobj) /* {{{ */ { - if (!zobj->properties) { - return rebuild_object_properties_internal(zobj); - } - return zobj->properties; + return zend_std_get_properties_ex(zobj); } /* }}} */ +/* Fetch properties HashTable without triggering lazy initialization */ +ZEND_API HashTable *zend_get_properties_no_init(zend_object *zobj) +{ + if (zobj->handlers->get_properties == zend_std_get_properties) { + if (UNEXPECTED(zend_object_is_lazy_proxy(zobj) + && zend_lazy_object_initialized(zobj))) { + zend_object *instance = zend_lazy_object_get_instance(zobj); + return zend_get_properties_no_init(instance); + } + + if (!zobj->properties) { + rebuild_object_properties_internal(zobj); + } + return zobj->properties; + } + + return zobj->handlers->get_properties(zobj); +} + ZEND_API HashTable *zend_std_get_gc(zend_object *zobj, zval **table, int *n) /* {{{ */ { if (zobj->handlers->get_properties != zend_std_get_properties) { @@ -144,7 +163,37 @@ ZEND_API HashTable *zend_std_get_gc(zend_object *zobj, zval **table, int *n) /* *n = 0; return zobj->handlers->get_properties(zobj); } else { - if (zobj->properties) { + if (UNEXPECTED(zend_object_is_lazy(zobj))) { + zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create(); + if (zend_lazy_object_initialized(zobj)) { + ZEND_ASSERT(zend_object_is_lazy_proxy(zobj)); + zend_object *instance = zend_lazy_object_get_instance(zobj); + zend_get_gc_buffer_add_obj(gc_buffer, instance); + } else { + zend_fcall_info_cache* initializer = zend_lazy_object_get_initializer_fcc(zobj); + if (initializer) { + // TODO: also expose _get_initializer_zv() to the GC + if (initializer->object) { + zend_get_gc_buffer_add_obj(gc_buffer, initializer->object); + } + if (initializer->closure) { + zend_get_gc_buffer_add_obj(gc_buffer, initializer->closure); + } + } + } + if (zobj->properties) { + zend_get_gc_buffer_use(gc_buffer, table, n); + return zobj->properties; + } else { + zval *prop = zobj->properties_table; + zval *end = prop + zobj->ce->default_properties_count; + for ( ; prop < end; prop++) { + zend_get_gc_buffer_add_zval(gc_buffer, prop); + } + zend_get_gc_buffer_use(gc_buffer, table, n); + return NULL; + } + } else if (zobj->properties) { *table = NULL; *n = 0; return zobj->properties; @@ -164,6 +213,10 @@ ZEND_API HashTable *zend_std_get_debug_info(zend_object *object, int *is_temp) / HashTable *ht; if (!ce->__debugInfo) { + if (UNEXPECTED(zend_object_is_lazy(object))) { + return zend_lazy_object_debug_info(object, is_temp); + } + *is_temp = 0; return object->handlers->get_properties(object); } @@ -826,6 +879,8 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int goto exit; } + retval = &EG(uninitialized_zval); + /* magic isset */ if ((type == BP_VAR_IS) && zobj->ce->__isset) { zval tmp_result; @@ -894,6 +949,17 @@ 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); + if (!zobj) { + retval = &EG(uninitialized_zval); + goto exit; + } + + return zend_std_read_property(zobj, name, type, cache_slot, rv); + } + } if (type != BP_VAR_IS) { if (prop_info) { zend_typed_property_uninitialized_access(prop_info, name); @@ -1005,6 +1071,11 @@ found:; goto exit; } if (Z_PROP_FLAG_P(variable_ptr) & IS_PROP_UNINIT) { + if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { + if (Z_PROP_FLAG_P(variable_ptr) & IS_PROP_LAZY) { + goto lazy_init; + } + } /* Writes to uninitialized typed properties bypass __set(). */ goto write_std_property; } @@ -1082,6 +1153,10 @@ found:; OBJ_RELEASE(zobj); variable_ptr = value; } else if (EXPECTED(!IS_WRONG_PROPERTY_OFFSET(property_offset))) { + if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { + goto lazy_init; + } + goto write_std_property; } else { /* Trigger the correct error */ @@ -1092,6 +1167,9 @@ found:; } } else { ZEND_ASSERT(!IS_WRONG_PROPERTY_OFFSET(property_offset)); + if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { + goto lazy_init; + } write_std_property: if (EXPECTED(IS_VALID_PROPERTY_OFFSET(property_offset))) { variable_ptr = OBJ_PROP(zobj, property_offset); @@ -1122,6 +1200,14 @@ found:; exit: return variable_ptr; + +lazy_init: + zobj = zend_lazy_object_init(zobj); + if (UNEXPECTED(!zobj)) { + variable_ptr = &EG(error_zval); + goto exit; + } + return zend_std_write_property(zobj, name, value, cache_slot); } /* }}} */ @@ -1252,6 +1338,14 @@ ZEND_API zval *zend_std_get_property_ptr_ptr(zend_object *zobj, zend_string *nam if (EXPECTED(!zobj->ce->__get) || 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); + if (!zobj) { + return &EG(error_zval); + } + + return zend_std_get_property_ptr_ptr(zobj, name, type, cache_slot); + } if (UNEXPECTED(type == BP_VAR_RW || type == BP_VAR_R)) { if (prop_info) { zend_typed_property_uninitialized_access(prop_info, name); @@ -1302,13 +1396,21 @@ ZEND_API zval *zend_std_get_property_ptr_ptr(zend_object *zobj, zend_string *nam return &EG(error_zval); } } + if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { + zobj = zend_lazy_object_init(zobj); + if (!zobj) { + return &EG(error_zval); + } + + return zend_std_get_property_ptr_ptr(zobj, name, type, cache_slot); + } if (UNEXPECTED(!zobj->properties)) { rebuild_object_properties_internal(zobj); } if (UNEXPECTED(type == BP_VAR_RW || type == BP_VAR_R)) { zend_error(E_WARNING, "Undefined property: %s::$%s", ZSTR_VAL(zobj->ce->name), ZSTR_VAL(name)); } - retval = zend_hash_add(zobj->properties, name, &EG(uninitialized_zval)); + retval = zend_hash_add(zend_std_get_properties(zobj), name, &EG(uninitialized_zval)); } } else if (!IS_HOOKED_PROPERTY_OFFSET(property_offset) && zobj->ce->__get == NULL) { retval = &EG(error_zval); @@ -1368,6 +1470,14 @@ ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void return; } 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); + if (!zobj) { + return; + } + return zend_std_unset_property(zobj, name, cache_slot); + } + /* Reset the IS_PROP_UNINIT flag, if it exists and bypass __unset(). */ Z_PROP_FLAG_P(slot) = 0; return; @@ -1401,6 +1511,7 @@ ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void (*guard) |= IN_UNSET; /* prevent circular unsetting */ zend_std_call_unsetter(zobj, name); (*guard) &= ~IN_UNSET; + return; } else if (UNEXPECTED(IS_WRONG_PROPERTY_OFFSET(property_offset))) { /* Trigger the correct error */ zend_wrong_offset(zobj->ce, name); @@ -1410,6 +1521,14 @@ ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void /* Nothing to do: The property already does not exist. */ } } + + if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { + zobj = zend_lazy_object_init(zobj); + if (!zobj) { + return; + } + return zend_std_unset_property(zobj, name, cache_slot); + } } /* }}} */ @@ -2062,8 +2181,7 @@ ZEND_API int zend_std_has_property(zend_object *zobj, zend_string *name, int has } if (UNEXPECTED(Z_PROP_FLAG_P(value) & IS_PROP_UNINIT)) { /* Skip __isset() for uninitialized typed properties */ - result = false; - goto exit; + goto lazy_init; } } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(property_offset))) { if (EXPECTED(zobj->properties != NULL)) { @@ -2146,6 +2264,10 @@ ZEND_API int zend_std_has_property(zend_object *zobj, zend_string *name, int has goto exit; } + if (!zobj->ce->__isset) { + goto lazy_init; + } + result = false; if ((has_set_exists != ZEND_PROPERTY_EXISTS) && zobj->ce->__isset) { uint32_t *guard = zend_get_property_guard(zobj, name); @@ -2177,6 +2299,22 @@ ZEND_API int zend_std_has_property(zend_object *zobj, zend_string *name, int has exit: return result; + +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); + if (!zobj) { + result = 0; + goto exit; + } + + return zend_std_has_property(zobj, name, has_set_exists, cache_slot); + } + } + + result = 0; + goto exit; } /* }}} */ @@ -2259,14 +2397,29 @@ ZEND_API HashTable *zend_std_get_properties_for(zend_object *obj, zend_prop_purp if (obj->ce->num_hooked_props) { return zend_hooked_object_build_properties(obj); } - ZEND_FALLTHROUGH; - case ZEND_PROP_PURPOSE_ARRAY_CAST: - case ZEND_PROP_PURPOSE_SERIALIZE: ht = obj->handlers->get_properties(obj); if (ht) { GC_TRY_ADDREF(ht); } return ht; + case ZEND_PROP_PURPOSE_ARRAY_CAST: + ht = zend_get_properties_no_init(obj); + if (ht) { + GC_TRY_ADDREF(ht); + } + return ht; + case ZEND_PROP_PURPOSE_SERIALIZE: { + if (zend_object_is_lazy(obj) + && !zend_lazy_object_initialize_on_serialize(obj)) { + ht = zend_get_properties_no_init(obj); + } else { + ht = obj->handlers->get_properties(obj); + } + if (ht) { + GC_TRY_ADDREF(ht); + } + return ht; + } default: ZEND_UNREACHABLE(); return NULL; diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index 8ec2164413df5..7ac2051ea3870 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -24,6 +24,7 @@ #include "zend_types.h" #include "zend_property_hooks.h" +#include "zend_lazy_objects.h" struct _zend_property_info; @@ -251,6 +252,7 @@ ZEND_API ZEND_COLD bool zend_std_unset_static_property(zend_class_entry *ce, zen ZEND_API zend_function *zend_std_get_constructor(zend_object *object); ZEND_API struct _zend_property_info *zend_get_property_info(const zend_class_entry *ce, zend_string *member, int silent); ZEND_API HashTable *zend_std_get_properties(zend_object *object); +ZEND_API HashTable *zend_get_properties_no_init(zend_object *zobj); ZEND_API HashTable *zend_std_get_gc(zend_object *object, zval **table, int *n); ZEND_API HashTable *zend_std_get_debug_info(zend_object *object, int *is_temp); ZEND_API zend_result zend_std_cast_object_tostring(zend_object *object, zval *writeobj, int type); @@ -272,12 +274,19 @@ ZEND_API HashTable *rebuild_object_properties_internal(zend_object *zobj); static zend_always_inline HashTable *zend_std_get_properties_ex(zend_object *object) { + if (UNEXPECTED(zend_lazy_object_must_init(object))) { + zend_object *instance = zend_lazy_object_init(object); + if (EXPECTED(instance)) { + object = instance; + } + } if (!object->properties) { return rebuild_object_properties_internal(object); } return object->properties; } +/* Implements the fast path for array cast */ ZEND_API HashTable *zend_std_build_object_properties_array(zend_object *zobj); /* Handler for objects that cannot be meaningfully compared. diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index af4d1f265897a..bdfc2a814aa35 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -25,12 +25,14 @@ #include "zend_interfaces.h" #include "zend_exceptions.h" #include "zend_weakrefs.h" +#include "zend_lazy_objects.h" static zend_always_inline void _zend_object_std_init(zend_object *object, zend_class_entry *ce) { GC_SET_REFCOUNT(object, 1); GC_TYPE_INFO(object) = GC_OBJECT; object->ce = ce; + object->flags = 0; object->handlers = ce->default_object_handlers; object->properties = NULL; zend_objects_store_put(object); @@ -46,14 +48,8 @@ ZEND_API void ZEND_FASTCALL zend_object_std_init(zend_object *object, zend_class _zend_object_std_init(object, ce); } -ZEND_API void zend_object_std_dtor(zend_object *object) +void zend_object_dtor_dynamic_properties(zend_object *object) { - zval *p, *end; - - if (UNEXPECTED(GC_FLAGS(object) & IS_OBJ_WEAKLY_REFERENCED)) { - zend_weakrefs_notify(object); - } - if (object->properties) { if (EXPECTED(!(GC_FLAGS(object->properties) & IS_ARRAY_IMMUTABLE))) { if (EXPECTED(GC_DELREF(object->properties) == 0) @@ -62,20 +58,41 @@ ZEND_API void zend_object_std_dtor(zend_object *object) } } } +} + +void zend_object_dtor_property(zend_object *object, zval *p) +{ + if (Z_REFCOUNTED_P(p)) { + if (UNEXPECTED(Z_ISREF_P(p)) && + (ZEND_DEBUG || ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(p)))) { + zend_property_info *prop_info = zend_get_property_info_for_slot(object, p); + if (ZEND_TYPE_IS_SET(prop_info->type)) { + ZEND_REF_DEL_TYPE_SOURCE(Z_REF_P(p), prop_info); + } + } + i_zval_ptr_dtor(p); + } +} + +ZEND_API void zend_object_std_dtor(zend_object *object) +{ + zval *p, *end; + + if (UNEXPECTED(GC_FLAGS(object) & IS_OBJ_WEAKLY_REFERENCED)) { + zend_weakrefs_notify(object); + } + + if (UNEXPECTED(zend_object_is_lazy(object))) { + zend_lazy_object_del_info(object); + } + + zend_object_dtor_dynamic_properties(object); + p = object->properties_table; if (EXPECTED(object->ce->default_properties_count)) { end = p + object->ce->default_properties_count; do { - if (Z_REFCOUNTED_P(p)) { - if (UNEXPECTED(Z_ISREF_P(p)) && - (ZEND_DEBUG || ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(p)))) { - zend_property_info *prop_info = zend_get_property_info_for_slot(object, p); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - ZEND_REF_DEL_TYPE_SOURCE(Z_REF_P(p), prop_info); - } - } - i_zval_ptr_dtor(p); - } + zend_object_dtor_property(object, p); p++; } while (p != end); } @@ -99,6 +116,10 @@ ZEND_API void zend_objects_destroy_object(zend_object *object) zend_function *destructor = object->ce->destructor; if (destructor) { + if (UNEXPECTED(zend_object_is_lazy(object))) { + return; + } + zend_object *old_exception; const zend_op *old_opline_before_exception; @@ -286,18 +307,22 @@ ZEND_API zend_object *zend_objects_clone_obj(zend_object *old_object) { zend_object *new_object; - /* assume that create isn't overwritten, so when clone depends on the - * overwritten one then it must itself be overwritten */ - new_object = zend_objects_new(old_object->ce); - - /* zend_objects_clone_members() expect the properties to be initialized. */ - if (new_object->ce->default_properties_count) { - zval *p = new_object->properties_table; - zval *end = p + new_object->ce->default_properties_count; - do { - ZVAL_UNDEF(p); - p++; - } while (p != end); + if (UNEXPECTED(zend_object_is_lazy(old_object))) { + return zend_lazy_object_clone(old_object); + } else { + /* assume that create isn't overwritten, so when clone depends on the + * overwritten one then it must itself be overwritten */ + new_object = zend_objects_new(old_object->ce); + + /* zend_objects_clone_members() expect the properties to be initialized. */ + if (new_object->ce->default_properties_count) { + zval *p = new_object->properties_table; + zval *end = p + new_object->ce->default_properties_count; + do { + ZVAL_UNDEF(p); + p++; + } while (p != end); + } } zend_objects_clone_members(new_object, old_object); diff --git a/Zend/zend_objects.h b/Zend/zend_objects.h index 91d388154dd13..41e3bcd9594b1 100644 --- a/Zend/zend_objects.h +++ b/Zend/zend_objects.h @@ -30,6 +30,10 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object, ZEND_API void zend_object_std_dtor(zend_object *object); ZEND_API void zend_objects_destroy_object(zend_object *object); ZEND_API zend_object *zend_objects_clone_obj(zend_object *object); + +void zend_object_dtor_dynamic_properties(zend_object *object); +void zend_object_dtor_property(zend_object *object, zval *p); + END_EXTERN_C() #endif /* ZEND_OBJECTS_H */ diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 5331244731cac..a3446bdcc4a99 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -814,7 +814,8 @@ ZEND_API void ZEND_FASTCALL convert_to_array(zval *op) /* {{{ */ convert_scalar_to_array(op); } else if (Z_OBJ_P(op)->properties == NULL && Z_OBJ_HT_P(op)->get_properties_for == NULL - && Z_OBJ_HT_P(op)->get_properties == zend_std_get_properties) { + && Z_OBJ_HT_P(op)->get_properties == zend_std_get_properties + && (!zend_object_is_lazy_proxy(Z_OBJ_P(op)) && !zend_lazy_object_initialized(Z_OBJ_P(op)))) { /* Optimized version without rebuilding properties HashTable */ HashTable *ht = zend_std_build_object_properties_array(Z_OBJ_P(op)); OBJ_RELEASE(Z_OBJ_P(op)); diff --git a/Zend/zend_types.h b/Zend/zend_types.h index d33f8a33bcbe6..d6aec3a35b4bd 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -556,6 +556,7 @@ typedef struct _HashTableIterator { struct _zend_object { zend_refcounted_h gc; uint32_t handle; // TODO: may be removed ??? + uint32_t flags; zend_class_entry *ce; const zend_object_handlers *handlers; HashTable *properties; @@ -829,6 +830,13 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) { #define OBJ_FLAGS(obj) GC_FLAGS(obj) +/* object extra flags (zend_object.flags) */ + +#define IS_OBJ_LAZY (1U<<31) /* Virtual proxy or uninitialized Ghost */ +#define IS_OBJ_LAZY_PROXY (1U<<30) /* Virtual proxy (may be initialized) */ + +#define OBJ_EXTRA_FLAGS(obj) ((obj)->flags) + /* Fast class cache */ #define ZSTR_HAS_CE_CACHE(s) (GC_FLAGS(s) & IS_STR_CLASS_NAME_MAP_PTR) #define ZSTR_GET_CE_CACHE(s) ZSTR_GET_CE_CACHE_EX(s, 1) @@ -1556,6 +1564,7 @@ static zend_always_inline uint32_t zval_delref_p(zval* pz) { * macros for this purpose, so this workaround is easier to remove in the future. */ #define IS_PROP_UNINIT (1<<0) #define IS_PROP_REINITABLE (1<<1) /* It has impact only on readonly properties */ +#define IS_PROP_LAZY (1<<2) #define Z_PROP_FLAG_P(z) Z_EXTRA_P(z) #define ZVAL_COPY_VALUE_PROP(z, v) \ do { *(z) = *(v); } while (0) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 55fdb7d46582b..772bc27869121 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -6431,7 +6431,8 @@ ZEND_VM_COLD_CONST_HANDLER(51, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE) } } else if (Z_OBJ_P(expr)->properties == NULL && Z_OBJ_HT_P(expr)->get_properties_for == NULL - && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties) { + && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties + && (!zend_object_is_lazy_proxy(Z_OBJ_P(expr)) || !zend_lazy_object_initialized(Z_OBJ_P(expr)))) { /* Optimized version without rebuilding properties HashTable */ ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); } else { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 16455b6e0cd58..edcab7848cc10 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -5174,7 +5174,8 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CONST_H } } else if (Z_OBJ_P(expr)->properties == NULL && Z_OBJ_HT_P(expr)->get_properties_for == NULL - && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties) { + && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties + && (!zend_object_is_lazy_proxy(Z_OBJ_P(expr)) || !zend_lazy_object_initialized(Z_OBJ_P(expr)))) { /* Optimized version without rebuilding properties HashTable */ ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); } else { @@ -20047,7 +20048,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPC } } else if (Z_OBJ_P(expr)->properties == NULL && Z_OBJ_HT_P(expr)->get_properties_for == NULL - && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties) { + && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties + && (!zend_object_is_lazy_proxy(Z_OBJ_P(expr)) || !zend_lazy_object_initialized(Z_OBJ_P(expr)))) { /* Optimized version without rebuilding properties HashTable */ ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); } else { @@ -22700,7 +22702,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPC } } else if (Z_OBJ_P(expr)->properties == NULL && Z_OBJ_HT_P(expr)->get_properties_for == NULL - && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties) { + && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties + && (!zend_object_is_lazy_proxy(Z_OBJ_P(expr)) || !zend_lazy_object_initialized(Z_OBJ_P(expr)))) { /* Optimized version without rebuilding properties HashTable */ ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); } else { @@ -40745,7 +40748,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCO } } else if (Z_OBJ_P(expr)->properties == NULL && Z_OBJ_HT_P(expr)->get_properties_for == NULL - && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties) { + && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties + && (!zend_object_is_lazy_proxy(Z_OBJ_P(expr)) || !zend_lazy_object_initialized(Z_OBJ_P(expr)))) { /* Optimized version without rebuilding properties HashTable */ ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); } else { diff --git a/configure.ac b/configure.ac index 2693ba09f4af9..6a30788a2afce 100644 --- a/configure.ac +++ b/configure.ac @@ -1743,6 +1743,7 @@ PHP_ADD_SOURCES([Zend], m4_normalize([ zend_iterators.c zend_language_parser.c zend_language_scanner.c + zend_lazy_objects.c zend_list.c zend_llist.c zend_max_execution_timer.c diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index d53427523f4bc..f5fe23f955398 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -246,6 +246,7 @@ static zend_always_inline void zend_ffi_object_init(zend_object *object, zend_cl { GC_SET_REFCOUNT(object, 1); GC_TYPE_INFO(object) = GC_OBJECT | (IS_OBJ_DESTRUCTOR_CALLED << GC_FLAGS_SHIFT); + object->flags = 0; object->ce = ce; object->handlers = ce->default_object_handlers; object->properties = NULL; diff --git a/ext/json/json_encoder.c b/ext/json/json_encoder.c index 1e344cde436ff..6d28ab033336d 100644 --- a/ext/json/json_encoder.c +++ b/ext/json/json_encoder.c @@ -28,6 +28,7 @@ #include #include "zend_enum.h" #include "zend_property_hooks.h" +#include "zend_lazy_objects.h" static const char digits[] = "0123456789abcdef"; @@ -127,6 +128,14 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, && Z_OBJ_P(val)->ce->num_hooked_props == 0) { /* Optimized version without rebuilding properties HashTable */ zend_object *obj = Z_OBJ_P(val); + + if (zend_lazy_object_must_init(Z_OBJ_P(val))) { + obj = zend_lazy_object_init(Z_OBJ_P(val)); + if (!obj) { + return FAILURE; + } + } + zend_class_entry *ce = obj->ce; zend_property_info *prop_info; zval *prop; diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 1215fa8b1ad48..9354bf626877e 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -19,7 +19,11 @@ */ #include "zend_compile.h" +#include "zend_execute.h" +#include "zend_lazy_objects.h" +#include "zend_object_handlers.h" #include "zend_type_info.h" +#include "zend_types.h" #ifdef HAVE_CONFIG_H #include #endif @@ -474,7 +478,7 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char smart_str_append_printf(str, "%s }\n", indent); if (obj && Z_TYPE_P(obj) == IS_OBJECT) { - HashTable *properties = Z_OBJ_HT_P(obj)->get_properties(Z_OBJ_P(obj)); + HashTable *properties = zend_get_properties_no_init(Z_OBJ_P(obj)); zend_string *prop_name; smart_str prop_str = {0}; @@ -5187,6 +5191,195 @@ ZEND_METHOD(ReflectionClass, newInstanceArgs) } /* }}} */ +void reflection_class_new_lazy(INTERNAL_FUNCTION_PARAMETERS, + int strategy, bool is_reset) +{ + reflection_object *intern; + zend_object *obj; + zend_class_entry *ce; + zend_fcall_info fci; + zend_fcall_info_cache fcc; + zend_long flags = 0; + + ZEND_ASSERT(strategy == ZEND_LAZY_OBJECT_STRATEGY_GHOST + || strategy == ZEND_LAZY_OBJECT_STRATEGY_PROXY); + + GET_REFLECTION_OBJECT_PTR(ce); + + if (is_reset) { + ZEND_PARSE_PARAMETERS_START(2, 3) + // TODO: check that obj->ce matches ce + Z_PARAM_OBJ_OF_CLASS(obj, ce) + Z_PARAM_FUNC(fci, fcc) + Z_PARAM_OPTIONAL + // TODO: check named param + Z_PARAM_LONG(flags) + ZEND_PARSE_PARAMETERS_END(); + } else { + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_FUNC(fci, fcc) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(flags) + ZEND_PARSE_PARAMETERS_END(); + obj = NULL; + } + + if (flags & ~ZEND_LAZY_OBJECT_USER_FLAGS) { + zend_throw_exception_ex(reflection_exception_ptr, 0, "Invalid flags"); + RETURN_THROWS(); + } + + 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"); + RETURN_THROWS(); + } + } else { + obj = NULL; + } + + if (!fcc.function_handler) { + /* Call trampoline has been cleared by zpp. Refetch it, because we want to deal + * with it ourselves. It is important that it is not refetched on every call, + * because calls may occur from different scopes. */ + zend_is_callable_ex(&fci.function_name, NULL, 0, NULL, &fcc, NULL); + } + + obj = zend_object_make_lazy(obj, ce, &fci.function_name, &fcc, + strategy | flags); + + if (!obj) { + RETURN_THROWS(); + } + + if (!is_reset) { + RETURN_OBJ(obj); + } +} + +/* {{{ Instantiates a lazy instance, using the ghost strategy */ +PHP_METHOD(ReflectionClass, newLazyGhost) +{ + reflection_class_new_lazy(INTERNAL_FUNCTION_PARAM_PASSTHRU, + ZEND_LAZY_OBJECT_STRATEGY_GHOST, /*is_make_lazy */ false); +} +/* }}} */ + +/* {{{ Instantiates a lazy instance, using the proxy strategy */ +PHP_METHOD(ReflectionClass, newLazyProxy) +{ + reflection_class_new_lazy(INTERNAL_FUNCTION_PARAM_PASSTHRU, + ZEND_LAZY_OBJECT_STRATEGY_PROXY, /*is_make_lazy */ false); +} +/* }}} */ + +/* {{{ Reset an object and make it lazy, using the ghost strategy */ +PHP_METHOD(ReflectionClass, resetAsLazyGhost) +{ + reflection_class_new_lazy(INTERNAL_FUNCTION_PARAM_PASSTHRU, + ZEND_LAZY_OBJECT_STRATEGY_GHOST, /* is_reset */ true); +} +/* }}} */ + +/* {{{ Reset an object and make it lazy, using the proxy strategy */ +PHP_METHOD(ReflectionClass, resetAsLazyProxy) +{ + reflection_class_new_lazy(INTERNAL_FUNCTION_PARAM_PASSTHRU, + ZEND_LAZY_OBJECT_STRATEGY_PROXY, /*is_reset */ true); +} +/* }}} */ + +/* {{{ Returns whether object lazy and uninitialized */ +ZEND_METHOD(ReflectionClass, isUninitializedLazyObject) +{ + reflection_object *intern; + zend_class_entry *ce; + zend_object *object; + + GET_REFLECTION_OBJECT_PTR(ce); + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJ_OF_CLASS(object, ce) + ZEND_PARSE_PARAMETERS_END(); + + RETURN_BOOL(zend_object_is_lazy(object) && !zend_lazy_object_initialized(object)); +} +/* }}} */ + +/* {{{ Trigger object initialization */ +ZEND_METHOD(ReflectionClass, initializeLazyObject) +{ + reflection_object *intern; + zend_class_entry *ce; + zend_object *object; + + GET_REFLECTION_OBJECT_PTR(ce); + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJ_OF_CLASS(object, ce) + ZEND_PARSE_PARAMETERS_END(); + + if (zend_object_is_lazy(object) + && !zend_lazy_object_initialized(object)) { + zend_lazy_object_init(object); + } + + if (zend_lazy_object_initialized(object)) { + RETURN_OBJ_COPY(zend_lazy_object_get_instance(object)); + } else { + ZEND_ASSERT(EG(exception)); + } +} +/* }}} */ + +/* {{{ Mark object as initialized without calling the initializer */ +ZEND_METHOD(ReflectionClass, markLazyObjectAsInitialized) +{ + reflection_object *intern; + zend_class_entry *ce; + zend_object *object; + + GET_REFLECTION_OBJECT_PTR(ce); + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJ_OF_CLASS(object, ce) + ZEND_PARSE_PARAMETERS_END(); + + if (zend_object_is_lazy(object) + && !zend_lazy_object_initialized(object)) { + zend_lazy_object_mark_as_initialized(object); + } + + if (zend_lazy_object_initialized(object)) { + RETURN_OBJ_COPY(zend_lazy_object_get_instance(object)); + } else { + ZEND_ASSERT(EG(exception)); + } +} +/* }}} */ + +/* {{{ Get lazy object initializer */ +ZEND_METHOD(ReflectionClass, getLazyInitializer) +{ + reflection_object *intern; + zend_class_entry *ce; + zend_object *object; + + GET_REFLECTION_OBJECT_PTR(ce); + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJ_OF_CLASS(object, ce) + ZEND_PARSE_PARAMETERS_END(); + + if (!zend_object_is_lazy(object) + || zend_lazy_object_initialized(object)) { + return; + } + + RETURN_ZVAL(zend_lazy_object_get_initializer_zv(object), 1, 0); +} +/* }}} */ + /* {{{ Returns an array of interfaces this class implements */ ZEND_METHOD(ReflectionClass, getInterfaces) { @@ -5916,6 +6109,148 @@ ZEND_METHOD(ReflectionProperty, setRawValue) } } +/* {{{ Set property value withtout triggering initializer while skipping hooks if any */ +ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization) +{ + reflection_object *intern; + property_reference *ref; + zend_object *object; + zval *value; + + GET_REFLECTION_OBJECT_PTR(ref); + + if (!ref->prop) { + zend_throw_exception_ex(reflection_exception_ptr, 0, + "Can not use setRawValueWithoutLazyInitialization on dynamic property %s::$%s", + ZSTR_VAL(intern->ce->name), ZSTR_VAL(ref->unmangled_name)); + RETURN_THROWS(); + } + + if (ref->prop->flags & ZEND_ACC_STATIC) { + zend_throw_exception_ex(reflection_exception_ptr, 0, + "Can not use setRawValueWithoutLazyInitialization on static property %s::$%s", + ZSTR_VAL(intern->ce->name), ZSTR_VAL(ref->unmangled_name)); + RETURN_THROWS(); + } + + if (ref->prop->flags & ZEND_ACC_VIRTUAL) { + zend_throw_exception_ex(reflection_exception_ptr, 0, + "Can not use setRawValueWithoutLazyInitialization on virtual property %s::$%s", + ZSTR_VAL(intern->ce->name), ZSTR_VAL(ref->unmangled_name)); + RETURN_THROWS(); + } + + ZEND_PARSE_PARAMETERS_START(2, 2) { + Z_PARAM_OBJ_OF_CLASS(object, intern->ce) + Z_PARAM_ZVAL(value) + } ZEND_PARSE_PARAMETERS_END(); + + if (object->handlers->write_property != zend_std_write_property) { + zend_throw_exception_ex(reflection_exception_ptr, 0, + "Can not use setRawValueWithoutLazyInitialization on internal class %s", + ZSTR_VAL(intern->ce->name)); + RETURN_THROWS(); + } + + ZEND_ASSERT(IS_VALID_PROPERTY_OFFSET(ref->prop->offset)); + + zval *var_ptr = OBJ_PROP(object, ref->prop->offset); + bool prop_was_lazy = Z_PROP_FLAG_P(var_ptr) & IS_PROP_LAZY; + + /* Do not trigger initialization */ + Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_LAZY; + + if (!ref->prop || !ref->prop->hooks || !ref->prop->hooks[ZEND_PROPERTY_HOOK_SET]) { + zend_update_property_ex(intern->ce, object, ref->unmangled_name, value); + } else { + zend_function *func = zend_get_property_hook_trampoline(ref->prop, ZEND_PROPERTY_HOOK_SET, ref->unmangled_name); + zend_call_known_instance_method_with_1_params(func, object, NULL, value); + } + + /* Mark property as lazy again if an exception prevented update */ + if (EG(exception) && Z_TYPE_P(var_ptr) == IS_UNDEF + && zend_object_is_lazy(object) + && !zend_lazy_object_initialized(object)) { + Z_PROP_FLAG_P(var_ptr) |= IS_PROP_LAZY; + } + + /* Object becomes non-lazy if this was the last lazy prop */ + if (prop_was_lazy && !(Z_PROP_FLAG_P(var_ptr) & IS_PROP_LAZY) + && zend_object_is_lazy(object) + && !zend_lazy_object_initialized(object)) { + if (zend_lazy_object_decr_lazy_props(object)) { + zend_lazy_object_realize(object); + } + } +} + +/* {{{ Mark property as non-lazy, and initialize to default value */ +ZEND_METHOD(ReflectionProperty, skipLazyInitialization) +{ + reflection_object *intern; + property_reference *ref; + zend_object *object; + + GET_REFLECTION_OBJECT_PTR(ref); + + if (!ref->prop) { + zend_throw_exception_ex(reflection_exception_ptr, 0, + "Can not use skipLazyInitialization on dynamic property %s::$%s", + ZSTR_VAL(intern->ce->name), ZSTR_VAL(ref->unmangled_name)); + RETURN_THROWS(); + } + + if (ref->prop->flags & ZEND_ACC_STATIC) { + zend_throw_exception_ex(reflection_exception_ptr, 0, + "Can not use skipLazyInitialization on static property %s::$%s", + ZSTR_VAL(intern->ce->name), ZSTR_VAL(ref->unmangled_name)); + RETURN_THROWS(); + } + + if (ref->prop->flags & ZEND_ACC_VIRTUAL) { + zend_throw_exception_ex(reflection_exception_ptr, 0, + "Can not use skipLazyInitialization on virtual property %s::$%s", + ZSTR_VAL(intern->ce->name), ZSTR_VAL(ref->unmangled_name)); + RETURN_THROWS(); + } + + ZEND_PARSE_PARAMETERS_START(1, 1) { + Z_PARAM_OBJ_OF_CLASS(object, intern->ce) + } ZEND_PARSE_PARAMETERS_END(); + + if (object->handlers->write_property != zend_std_write_property) { + zend_throw_exception_ex(reflection_exception_ptr, 0, + "Can not use skipLazyInitialization on internal class %s", + ZSTR_VAL(intern->ce->name)); + RETURN_THROWS(); + } + + ZEND_ASSERT(IS_VALID_PROPERTY_OFFSET(ref->prop->offset)); + + bool prop_was_lazy = (Z_PROP_FLAG_P(OBJ_PROP(object, ref->prop->offset)) & IS_PROP_LAZY); + + zval *src = &object->ce->default_properties_table[OBJ_PROP_TO_NUM(ref->prop->offset)]; + zval *dst = OBJ_PROP(object, ref->prop->offset); + + if (!(Z_PROP_FLAG_P(dst) & IS_PROP_LAZY)) { + /* skipLazyInitialization has no effect on non-lazy properties */ + return; + } + + ZEND_ASSERT(Z_TYPE_P(dst) == IS_UNDEF && "Lazy property should be UNDEF"); + + ZVAL_COPY_OR_DUP_PROP(dst, src); + Z_PROP_FLAG_P(dst) &= ~(IS_PROP_LAZY | IS_PROP_REINITABLE); + + /* Object becomes non-lazy if this was the last lazy prop */ + if (prop_was_lazy && zend_object_is_lazy(object) + && !zend_lazy_object_initialized(object)) { + if (zend_lazy_object_decr_lazy_props(object)) { + zend_lazy_object_realize(object); + } + } +} + /* {{{ Returns true if property was initialized */ ZEND_METHOD(ReflectionProperty, isInitialized) { diff --git a/ext/reflection/php_reflection.h b/ext/reflection/php_reflection.h index 6420b04520aa6..d676597fd0bed 100644 --- a/ext/reflection/php_reflection.h +++ b/ext/reflection/php_reflection.h @@ -47,6 +47,7 @@ extern PHPAPI zend_class_entry *reflection_enum_ptr; extern PHPAPI zend_class_entry *reflection_enum_unit_case_ptr; extern PHPAPI zend_class_entry *reflection_enum_backed_case_ptr; extern PHPAPI zend_class_entry *reflection_fiber_ptr; +extern PHPAPI zend_class_entry *reflection_lazy_object_ptr; PHPAPI void zend_reflection_class_factory(zend_class_entry *ce, zval *object); diff --git a/ext/reflection/php_reflection.stub.php b/ext/reflection/php_reflection.stub.php index 2bb9a9a5efa01..366c13f3a1a1d 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -250,6 +250,12 @@ class ReflectionClass implements Reflector /** @cvalue ZEND_ACC_READONLY_CLASS */ public const int IS_READONLY = UNKNOWN; + /** @cvalue ZEND_LAZY_OBJECT_SKIP_INITIALIZATION_ON_SERIALIZE */ + public const int SKIP_INITIALIZATION_ON_SERIALIZE = UNKNOWN; + + /** @cvalue ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR */ + public const int SKIP_DESTRUCTOR = UNKNOWN; + public string $name; private function __clone(): void {} @@ -370,6 +376,22 @@ public function newInstanceWithoutConstructor(): object {} /** @tentative-return-type */ public function newInstanceArgs(array $args = []): ?object {} + public function newLazyGhost(callable $initializer, int $options = 0): object {} + + public function newLazyProxy(callable $factory, int $options = 0): object {} + + public function resetAsLazyGhost(object $object, callable $factory, int $options = 0): void {} + + public function resetAsLazyProxy(object $object, callable $factory, int $options = 0): void {} + + public function initializeLazyObject(object $object): object {} + + public function isUninitializedLazyObject(object $object): bool {} + + public function markLazyObjectAsInitialized(object $object): object {} + + public function getLazyInitializer(object $object): ?callable {} + /** @tentative-return-type */ public function getParentClass(): ReflectionClass|false {} @@ -472,6 +494,10 @@ public function getRawValue(object $object): mixed {} public function setRawValue(object $object, mixed $value): void {} + public function setRawValueWithoutLazyInitialization(object $object, mixed $value): void {} + + public function skipLazyInitialization(object $object): void {} + /** @tentative-return-type */ public function isInitialized(?object $object = null): bool {} diff --git a/ext/reflection/php_reflection_arginfo.h b/ext/reflection/php_reflection_arginfo.h index 19812c409c053..5d95b25582988 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: 28fde6ed0e247201ee25d608d27a4c5b0bb8f2f7 */ + * Stub hash: 09e21577c53d8b53e30aa30e3208d3807ecd8852 */ 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) @@ -287,6 +287,38 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionClass_ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, args, IS_ARRAY, 0, "[]") ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionClass_newLazyGhost, 0, 1, IS_OBJECT, 0) + ZEND_ARG_TYPE_INFO(0, initializer, IS_CALLABLE, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_LONG, 0, "0") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionClass_newLazyProxy, 0, 1, IS_OBJECT, 0) + ZEND_ARG_TYPE_INFO(0, factory, IS_CALLABLE, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_LONG, 0, "0") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionClass_resetAsLazyGhost, 0, 2, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0) + ZEND_ARG_TYPE_INFO(0, factory, IS_CALLABLE, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_LONG, 0, "0") +ZEND_END_ARG_INFO() + +#define arginfo_class_ReflectionClass_resetAsLazyProxy arginfo_class_ReflectionClass_resetAsLazyGhost + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionClass_initializeLazyObject, 0, 1, IS_OBJECT, 0) + ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionClass_isUninitializedLazyObject, 0, 1, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_ReflectionClass_markLazyObjectAsInitialized arginfo_class_ReflectionClass_initializeLazyObject + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionClass_getLazyInitializer, 0, 1, IS_CALLABLE, 1) + ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_ReflectionClass_getParentClass, 0, 0, ReflectionClass, MAY_BE_FALSE) ZEND_END_ARG_INFO() @@ -361,6 +393,12 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionProperty_setRawV ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) ZEND_END_ARG_INFO() +#define arginfo_class_ReflectionProperty_setRawValueWithoutLazyInitialization arginfo_class_ReflectionProperty_setRawValue + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionProperty_skipLazyInitialization, 0, 1, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionProperty_isInitialized, 0, 0, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, object, IS_OBJECT, 1, "null") ZEND_END_ARG_INFO() @@ -763,6 +801,14 @@ ZEND_METHOD(ReflectionClass, isInstance); ZEND_METHOD(ReflectionClass, newInstance); ZEND_METHOD(ReflectionClass, newInstanceWithoutConstructor); ZEND_METHOD(ReflectionClass, newInstanceArgs); +ZEND_METHOD(ReflectionClass, newLazyGhost); +ZEND_METHOD(ReflectionClass, newLazyProxy); +ZEND_METHOD(ReflectionClass, resetAsLazyGhost); +ZEND_METHOD(ReflectionClass, resetAsLazyProxy); +ZEND_METHOD(ReflectionClass, initializeLazyObject); +ZEND_METHOD(ReflectionClass, isUninitializedLazyObject); +ZEND_METHOD(ReflectionClass, markLazyObjectAsInitialized); +ZEND_METHOD(ReflectionClass, getLazyInitializer); ZEND_METHOD(ReflectionClass, getParentClass); ZEND_METHOD(ReflectionClass, isSubclassOf); ZEND_METHOD(ReflectionClass, getStaticProperties); @@ -785,6 +831,8 @@ ZEND_METHOD(ReflectionProperty, getValue); ZEND_METHOD(ReflectionProperty, setValue); ZEND_METHOD(ReflectionProperty, getRawValue); ZEND_METHOD(ReflectionProperty, setRawValue); +ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization); +ZEND_METHOD(ReflectionProperty, skipLazyInitialization); ZEND_METHOD(ReflectionProperty, isInitialized); ZEND_METHOD(ReflectionProperty, isPublic); ZEND_METHOD(ReflectionProperty, isPrivate); @@ -1044,6 +1092,14 @@ static const zend_function_entry class_ReflectionClass_methods[] = { ZEND_ME(ReflectionClass, newInstance, arginfo_class_ReflectionClass_newInstance, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionClass, newInstanceWithoutConstructor, arginfo_class_ReflectionClass_newInstanceWithoutConstructor, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionClass, newInstanceArgs, arginfo_class_ReflectionClass_newInstanceArgs, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionClass, newLazyGhost, arginfo_class_ReflectionClass_newLazyGhost, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionClass, newLazyProxy, arginfo_class_ReflectionClass_newLazyProxy, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionClass, resetAsLazyGhost, arginfo_class_ReflectionClass_resetAsLazyGhost, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionClass, resetAsLazyProxy, arginfo_class_ReflectionClass_resetAsLazyProxy, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionClass, initializeLazyObject, arginfo_class_ReflectionClass_initializeLazyObject, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionClass, isUninitializedLazyObject, arginfo_class_ReflectionClass_isUninitializedLazyObject, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionClass, markLazyObjectAsInitialized, arginfo_class_ReflectionClass_markLazyObjectAsInitialized, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionClass, getLazyInitializer, arginfo_class_ReflectionClass_getLazyInitializer, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionClass, getParentClass, arginfo_class_ReflectionClass_getParentClass, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionClass, isSubclassOf, arginfo_class_ReflectionClass_isSubclassOf, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionClass, getStaticProperties, arginfo_class_ReflectionClass_getStaticProperties, ZEND_ACC_PUBLIC) @@ -1080,6 +1136,8 @@ static const zend_function_entry class_ReflectionProperty_methods[] = { ZEND_ME(ReflectionProperty, setValue, arginfo_class_ReflectionProperty_setValue, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionProperty, getRawValue, arginfo_class_ReflectionProperty_getRawValue, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionProperty, setRawValue, arginfo_class_ReflectionProperty_setRawValue, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionProperty, setRawValueWithoutLazyInitialization, arginfo_class_ReflectionProperty_setRawValueWithoutLazyInitialization, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionProperty, skipLazyInitialization, arginfo_class_ReflectionProperty_skipLazyInitialization, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionProperty, isInitialized, arginfo_class_ReflectionProperty_isInitialized, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionProperty, isPublic, arginfo_class_ReflectionProperty_isPublic, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionProperty, isPrivate, arginfo_class_ReflectionProperty_isPrivate, ZEND_ACC_PUBLIC) @@ -1443,6 +1501,18 @@ static zend_class_entry *register_class_ReflectionClass(zend_class_entry *class_ zend_declare_typed_class_constant(class_entry, const_IS_READONLY_name, &const_IS_READONLY_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_IS_READONLY_name); + zval const_SKIP_INITIALIZATION_ON_SERIALIZE_value; + ZVAL_LONG(&const_SKIP_INITIALIZATION_ON_SERIALIZE_value, ZEND_LAZY_OBJECT_SKIP_INITIALIZATION_ON_SERIALIZE); + zend_string *const_SKIP_INITIALIZATION_ON_SERIALIZE_name = zend_string_init_interned("SKIP_INITIALIZATION_ON_SERIALIZE", sizeof("SKIP_INITIALIZATION_ON_SERIALIZE") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_SKIP_INITIALIZATION_ON_SERIALIZE_name, &const_SKIP_INITIALIZATION_ON_SERIALIZE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_SKIP_INITIALIZATION_ON_SERIALIZE_name); + + zval const_SKIP_DESTRUCTOR_value; + ZVAL_LONG(&const_SKIP_DESTRUCTOR_value, ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR); + zend_string *const_SKIP_DESTRUCTOR_name = zend_string_init_interned("SKIP_DESTRUCTOR", sizeof("SKIP_DESTRUCTOR") - 1, 1); + 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 property_name_default_value; ZVAL_UNDEF(&property_name_default_value); zend_string *property_name_name = zend_string_init("name", sizeof("name") - 1, 1); diff --git a/ext/reflection/tests/ReflectionClass_toString_001.phpt b/ext/reflection/tests/ReflectionClass_toString_001.phpt index 15059211ef01d..9b5c7db436b09 100644 --- a/ext/reflection/tests/ReflectionClass_toString_001.phpt +++ b/ext/reflection/tests/ReflectionClass_toString_001.phpt @@ -11,11 +11,13 @@ echo $rc; --EXPECT-- Class [ class ReflectionClass implements Stringable, Reflector ] { - - Constants [4] { + - Constants [6] { 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 } } - Static properties [0] { @@ -28,7 +30,7 @@ Class [ class ReflectionClass implements Stringable, Refle Property [ public string $name ] } - - Methods [56] { + - Methods [64] { Method [ private method __clone ] { - Parameters [0] { @@ -330,6 +332,76 @@ Class [ class ReflectionClass implements Stringable, Refle - Tentative return [ ?object ] } + Method [ public method newLazyGhost ] { + + - Parameters [2] { + Parameter #0 [ callable $initializer ] + Parameter #1 [ int $options = 0 ] + } + - Return [ object ] + } + + Method [ public method newLazyProxy ] { + + - Parameters [2] { + Parameter #0 [ callable $factory ] + Parameter #1 [ int $options = 0 ] + } + - Return [ object ] + } + + Method [ public method resetAsLazyGhost ] { + + - Parameters [3] { + Parameter #0 [ object $object ] + Parameter #1 [ callable $factory ] + Parameter #2 [ int $options = 0 ] + } + - Return [ void ] + } + + Method [ public method resetAsLazyProxy ] { + + - Parameters [3] { + Parameter #0 [ object $object ] + Parameter #1 [ callable $factory ] + Parameter #2 [ int $options = 0 ] + } + - Return [ void ] + } + + Method [ public method initializeLazyObject ] { + + - Parameters [1] { + Parameter #0 [ object $object ] + } + - Return [ object ] + } + + Method [ public method isUninitializedLazyObject ] { + + - Parameters [1] { + Parameter #0 [ object $object ] + } + - Return [ bool ] + } + + Method [ public method markLazyObjectAsInitialized ] { + + - Parameters [1] { + Parameter #0 [ object $object ] + } + - Return [ object ] + } + + Method [ public method getLazyInitializer ] { + + - Parameters [1] { + Parameter #0 [ object $object ] + } + - Return [ ?callable ] + } + Method [ public method getParentClass ] { - Parameters [0] { diff --git a/ext/standard/var.c b/ext/standard/var.c index 7e51a23e3c029..479412de4aea2 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -23,11 +23,13 @@ #include "php.h" #include "php_string.h" #include "php_var.h" +#include "zend_lazy_objects.h" #include "zend_smart_str.h" #include "basic_functions.h" #include "php_incomplete_class.h" #include "zend_enum.h" #include "zend_exceptions.h" +#include "zend_types.h" /* }}} */ struct php_serialize_data { @@ -163,7 +165,19 @@ PHPAPI void php_var_dump(zval *struc, int level) /* {{{ */ myht = zend_get_properties_for(struc, ZEND_PROP_PURPOSE_DEBUG); class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc)); - php_printf("%sobject(%s)#%d (%d) {\n", COMMON, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0); + + const char *prefix; + if (zend_object_is_lazy(Z_OBJ_P(struc))) { + if (zend_object_is_lazy_proxy(Z_OBJ_P(struc))) { + prefix = "lazy proxy "; + } else { + prefix = "lazy ghost "; + } + } else { + prefix = ""; + } + + php_printf("%s%sobject(%s)#%d (%d) {\n", COMMON, prefix, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0); zend_string_release_ex(class_name, 0); if (myht) { @@ -360,7 +374,19 @@ PHPAPI void php_debug_zval_dump(zval *struc, int level) /* {{{ */ myht = zend_get_properties_for(struc, ZEND_PROP_PURPOSE_DEBUG); class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc)); - php_printf("object(%s)#%d (%d) refcount(%u){\n", ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0, Z_REFCOUNT_P(struc)); + + const char *prefix; + if (zend_object_is_lazy(Z_OBJ_P(struc))) { + if (zend_object_is_lazy_proxy(Z_OBJ_P(struc))) { + prefix = "lazy proxy "; + } else { + prefix = "lazy ghost "; + } + } else { + prefix = ""; + } + + php_printf("%sobject(%s)#%d (%d) refcount(%u){\n", prefix, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0, Z_REFCOUNT_P(struc)); zend_string_release_ex(class_name, 0); if (myht) { ZEND_HASH_FOREACH_KEY_VAL(myht, index, key, val) { @@ -1209,6 +1235,16 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_ && Z_OBJ_HT_P(struc)->get_properties == zend_std_get_properties) { /* Optimized version without rebulding properties HashTable */ zend_object *obj = Z_OBJ_P(struc); + + if (zend_lazy_object_must_init(Z_OBJ_P(struc)) + && zend_lazy_object_initialize_on_serialize(Z_OBJ_P(struc))) { + obj = zend_lazy_object_init(Z_OBJ_P(struc)); + if (!obj) { + smart_str_appendl(buf, "N;", 2); + return; + } + } + zend_class_entry *ce = obj->ce; zend_property_info *prop_info; zval *prop; From c5901fc81fd119364de8c4aa08fd34bbb882e823 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Thu, 25 Jul 2024 19:07:10 +0200 Subject: [PATCH 02/56] Test cleanup --- Zend/tests/lazy_objects/016.phpt | 45 --------------- Zend/tests/lazy_objects/018.phpt | 57 ------------------- ...002.phpt => clone_calls___clone_once.phpt} | 0 ...es_object_with_independent_state_001.phpt} | 2 +- ...es_object_with_independent_state_002.phpt} | 2 +- ...es_object_with_independent_state_003.phpt} | 2 +- ...{clone_004.phpt => clone_initialized.phpt} | 0 ....phpt => clone_initializer_exception.phpt} | 0 ...{clone_001.phpt => clone_initializes.phpt} | 0 ...phpt => clone_preverves_object_class.phpt} | 7 ++- .../{017.phpt => dtor_called_if_init.phpt} | 20 ++----- .../dtor_not_called_if_not_init.phpt | 43 ++++++++++++++ Zend/tests/lazy_objects/feedback_006.phpt | 29 ---------- ...8.phpt => fetch_coalesce_initializes.phpt} | 8 +-- ...ch_coalesce_non_existing_initializes.phpt} | 8 +-- ...t => fetch_declared_prop_initializes.phpt} | 8 +-- ...pt => fetch_dynamic_prop_initializes.phpt} | 8 +-- ...hpt => fetch_hook_may_not_initialize.phpt} | 10 ++-- ...=> fetch_hook_virtual_may_initialize.phpt} | 10 ++-- ...etch_hook_virtual_may_not_initialize.phpt} | 10 ++-- ...t => fetch_magic_prop_may_initialize.phpt} | 10 ++-- ... fetch_magic_prop_may_not_initialize.phpt} | 10 ++-- ..._magic_prop_recursive_may_initialize.phpt} | 10 ++-- ...h_011.phpt => fetch_op_dynamic_error.phpt} | 8 +-- ...=> fetch_op_dynamic_prop_initializes.phpt} | 8 +-- .../{fetch_012.phpt => fetch_op_error.phpt} | 8 +-- ...tch_003.phpt => fetch_op_initializes.phpt} | 8 +-- ..._op_skipped_prop_does_not_initialize.phpt} | 8 +-- ...ch_010.phpt => fetch_ref_initializes.phpt} | 8 +-- ...ref_skipped_prop_does_not_initialize.phpt} | 8 +-- ...tch_skipped_prop_does_not_initialize.phpt} | 8 +-- ...al_classes_can_be_initialized_lazily.phpt} | 8 +-- .../{feedback_002.phpt => gc_006.phpt} | 2 +- ...ast_const_001.phpt => init_ast_const.phpt} | 0 ...t_002.phpt => init_ast_const_failure.phpt} | 0 ...=> init_exception_leaves_object_lazy.phpt} | 14 +++-- ...xception_reverts_initializer_changes.phpt} | 16 +++--- ...everts_initializer_changes_dyn_props.phpt} | 16 +++--- ...initializer_changes_dyn_props_and_ht.phpt} | 16 +++--- ...n_reverts_initializer_changes_nested.phpt} | 2 +- ..._initializer_changes_overridden_prop.phpt} | 13 +++-- ...reverts_initializer_changes_props_ht.phpt} | 16 +++--- ...rts_initializer_changes_props_ht_ref.phpt} | 16 +++--- .../{024.phpt => init_fatal.phpt} | 3 +- ...hpt => init_handles_ref_source_types.phpt} | 16 +++--- ...t_handles_ref_source_types_exception.phpt} | 15 ++--- ....phpt => init_may_leave_props_uninit.phpt} | 7 ++- ..._004.phpt => init_preserves_identity.phpt} | 2 +- ...3.phpt => init_preserves_proxy_class.phpt} | 2 +- ...hpt => init_sets_prop_default_values.phpt} | 7 ++- ...{012.phpt => init_trigger_array_cast.phpt} | 8 +-- ...phpt => init_trigger_debug_zval_dump.phpt} | 0 .../{006.phpt => init_trigger_foreach.phpt} | 8 +-- ...init_trigger_get_mangled_object_vars.phpt} | 8 +-- ...phpt => init_trigger_get_object_vars.phpt} | 8 +-- ...010.phpt => init_trigger_json_encode.phpt} | 8 +-- ...t_trigger_reflection_object_toString.phpt} | 8 +-- .../{009.phpt => init_trigger_serialize.phpt} | 8 +-- .../{007.phpt => init_trigger_var_dump.phpt} | 1 - ...init_trigger_var_dump_debug_info_001.phpt} | 12 ++-- ...init_trigger_var_dump_debug_info_002.phpt} | 11 ++-- ...{008.phpt => init_trigger_var_export.phpt} | 8 +-- ...ize_001.phpt => initializeLazyObject.phpt} | 10 ++-- ...5.phpt => initializeLazyObject_error.phpt} | 10 ++-- ...azyObject_noop_on_initialized_object.phpt} | 16 +++--- ...itializer_must_return_the_right_type.phpt} | 12 ++-- .../isUninitializedLazyObject.phpt | 49 ++++++++++++++++ .../lazy_objects/is_initialized_001.phpt | 26 --------- .../is_uninitialized_lazy_object.phpt | 31 ---------- ....phpt => isset_hooked_may_initialize.phpt} | 10 ++-- ...t => isset_hooked_may_not_initialize.phpt} | 10 ++-- ...{isset_001.phpt => isset_initializes.phpt} | 8 +-- ....phpt => markLazyObjectAsInitialized.phpt} | 10 ++-- .../lazy_objects/new_instance_lazy_001.phpt | 20 ------- .../lazy_objects/new_instance_lazy_002.phpt | 21 ------- .../lazy_objects/new_instance_lazy_003.phpt | 22 ------- .../lazy_objects/new_instance_lazy_004.phpt | 18 ------ .../lazy_objects/new_instance_lazy_005.phpt | 21 ------- .../{realize_001.phpt => realize.phpt} | 11 ++-- ...realize_003.phpt => realize_no_props.phpt} | 0 ...004.phpt => realize_proxy_overridden.phpt} | 11 ++-- ...{realize_002.phpt => realize_skipped.phpt} | 11 ++-- ...t => reset_as_lazy_already_exception.phpt} | 19 ++++--- ...pt => reset_as_lazy_calls_destructor.phpt} | 8 ++- ...s_lazy_deletes_reference_source_type.phpt} | 8 ++- ...> reset_as_lazy_destructor_exception.phpt} | 8 ++- ...t => reset_as_lazy_initialized_proxy.phpt} | 2 +- ..._as_lazy_may_call_nested_destructors.phpt} | 2 +- ...=> reset_as_lazy_may_skip_destructor.phpt} | 8 ++- ...y_001.phpt => reset_as_lazy_readonly.phpt} | 2 +- ....phpt => reset_as_lazy_real_instance.phpt} | 2 +- ...> reset_as_lazy_resets_dynamic_props.phpt} | 8 ++- .../{ => rfc}/rfc_example_001.phpt | 0 .../{ => rfc}/rfc_example_002.phpt | 0 .../{ => rfc}/rfc_example_003.phpt | 0 .../{ => rfc}/rfc_example_004.phpt | 0 .../{ => rfc}/rfc_example_005.phpt | 0 .../{ => rfc}/rfc_example_006.phpt | 0 .../{ => rfc}/rfc_example_007.phpt | 0 .../{ => rfc}/rfc_example_008.phpt | 0 .../{ => rfc}/rfc_example_009.phpt | 0 .../{ => rfc}/rfc_example_010.phpt | 0 .../{ => rfc}/rfc_example_011.phpt | 0 .../{ => rfc}/rfc_example_012.phpt | 0 ...serialize___serialize_may_initialize.phpt} | 10 ++-- ...alize___serialize_may_not_initialize.phpt} | 10 ++-- ...hpt => serialize___sleep_initializes.phpt} | 8 +-- ....phpt => serialize___sleep_skip_flag.phpt} | 8 +-- ...ize___sleep_skip_flag_may_initialize.phpt} | 10 ++-- ...serialize_010.phpt => serialize_hook.phpt} | 8 +-- ...ze_001.phpt => serialize_initializes.phpt} | 8 +-- ...alize_002.phpt => serialize_props_ht.phpt} | 8 +-- ...lize_003.phpt => serialize_skip_flag.phpt} | 8 +-- ...phpt => serialize_skip_flag_props_ht.phpt} | 8 +-- ...setRawValueWithoutLazyInitialization.phpt} | 0 ...eWithoutLazyInitialization_exception.phpt} | 0 ...ithoutLazyInitialization_initialized.phpt} | 0 ...utLazyInitialization_no_dynamic_prop.phpt} | 0 ...ueWithoutLazyInitialization_readonly.phpt} | 0 ...tLazyInitialization_readonly_variant.phpt} | 0 ...lueWithoutLazyInitialization_realize.phpt} | 0 ...yInitialization_side_effect_destruct.phpt} | 0 ...yInitialization_side_effect_toString.phpt} | 0 ...ithoutLazyInitialization_skips___set.phpt} | 0 ...WithoutLazyInitialization_skips_hook.phpt} | 0 ...y_001.phpt => skipLazyInitialization.phpt} | 2 +- ...pt => skipLazyInitialization_default.phpt} | 0 ...azyInitialization_initialized_object.phpt} | 0 ...ipLazyInitialization_no_dynamic_prop.phpt} | 0 ...t => skipLazyInitialization_readonly.phpt} | 0 ...pt => skipLazyInitialization_realize.phpt} | 0 ...> skipLazyInitialization_skips___set.phpt} | 0 ...> skipLazyInitialization_skips_hooks.phpt} | 0 ...zyInitialization_skips_non_lazy_prop.phpt} | 0 ....phpt => support_no_internal_classes.phpt} | 8 +-- ...t => support_no_internal_sub_classes.phpt} | 8 +-- .../{004.phpt => support_readonly_class.phpt} | 8 +-- .../{003.phpt => support_readonly_prop.phpt} | 8 +-- Zend/tests/lazy_objects/support_stdClass.phpt | 30 ++++++++++ .../support_stdClass_sub_classes.phpt | 33 +++++++++++ Zend/tests/lazy_objects/unclean_shutdown.phpt | 5 +- ....phpt => unset_defined_no_initialize.phpt} | 8 +-- .../{unset_010.phpt => unset_hook.phpt} | 8 +-- ... unset_magic_circular_may_initialize.phpt} | 8 +-- ...4.phpt => unset_magic_may_initialize.phpt} | 10 ++-- ...pt => unset_magic_may_not_initialize.phpt} | 10 ++-- ....phpt => unset_skipped_no_initialize.phpt} | 10 ++-- ... unset_undefined_dynamic_initializes.phpt} | 8 +-- ...ined_dynamic_initializes_no_props_ht.phpt} | 8 +-- ....phpt => unset_undefined_initializes.phpt} | 8 +-- Zend/tests/lazy_objects/use_case_001.phpt | 4 +- Zend/tests/lazy_objects/use_case_001b.phpt | 4 +- Zend/tests/lazy_objects/use_case_002.phpt | 8 +-- ...02.phpt => write_dynamic_initializes.phpt} | 10 ++-- ....phpt => write_initializer_exception.phpt} | 8 +-- ...{write_001.phpt => write_initializes.phpt} | 8 +-- ... write_magic_circular_may_initialize.phpt} | 8 +-- ...3.phpt => write_magic_may_initialize.phpt} | 10 ++-- ....phpt => write_skipped_no_initialize.phpt} | 10 ++-- 159 files changed, 623 insertions(+), 729 deletions(-) delete mode 100644 Zend/tests/lazy_objects/016.phpt delete mode 100644 Zend/tests/lazy_objects/018.phpt rename Zend/tests/lazy_objects/{clone_002.phpt => clone_calls___clone_once.phpt} (100%) rename Zend/tests/lazy_objects/{clone_007.phpt => clone_creates_object_with_independent_state_001.phpt} (92%) rename Zend/tests/lazy_objects/{clone_008.phpt => clone_creates_object_with_independent_state_002.phpt} (94%) rename Zend/tests/lazy_objects/{clone_009.phpt => clone_creates_object_with_independent_state_003.phpt} (92%) rename Zend/tests/lazy_objects/{clone_004.phpt => clone_initialized.phpt} (100%) rename Zend/tests/lazy_objects/{clone_003.phpt => clone_initializer_exception.phpt} (100%) rename Zend/tests/lazy_objects/{clone_001.phpt => clone_initializes.phpt} (100%) rename Zend/tests/lazy_objects/{feedback_007.phpt => clone_preverves_object_class.phpt} (76%) rename Zend/tests/lazy_objects/{017.phpt => dtor_called_if_init.phpt} (66%) create mode 100644 Zend/tests/lazy_objects/dtor_not_called_if_not_init.phpt delete mode 100644 Zend/tests/lazy_objects/feedback_006.phpt rename Zend/tests/lazy_objects/{fetch_008.phpt => fetch_coalesce_initializes.phpt} (76%) rename Zend/tests/lazy_objects/{fetch_009.phpt => fetch_coalesce_non_existing_initializes.phpt} (76%) rename Zend/tests/lazy_objects/{fetch_001.phpt => fetch_declared_prop_initializes.phpt} (77%) rename Zend/tests/lazy_objects/{fetch_002.phpt => fetch_dynamic_prop_initializes.phpt} (77%) rename Zend/tests/lazy_objects/{fetch_016.phpt => fetch_hook_may_not_initialize.phpt} (75%) rename Zend/tests/lazy_objects/{fetch_017.phpt => fetch_hook_virtual_may_initialize.phpt} (79%) rename Zend/tests/lazy_objects/{fetch_018.phpt => fetch_hook_virtual_may_not_initialize.phpt} (69%) rename Zend/tests/lazy_objects/{fetch_006.phpt => fetch_magic_prop_may_initialize.phpt} (72%) rename Zend/tests/lazy_objects/{fetch_005.phpt => fetch_magic_prop_may_not_initialize.phpt} (70%) rename Zend/tests/lazy_objects/{fetch_007.phpt => fetch_magic_prop_recursive_may_initialize.phpt} (74%) rename Zend/tests/lazy_objects/{fetch_011.phpt => fetch_op_dynamic_error.phpt} (76%) rename Zend/tests/lazy_objects/{fetch_004.phpt => fetch_op_dynamic_prop_initializes.phpt} (77%) rename Zend/tests/lazy_objects/{fetch_012.phpt => fetch_op_error.phpt} (75%) rename Zend/tests/lazy_objects/{fetch_003.phpt => fetch_op_initializes.phpt} (76%) rename Zend/tests/lazy_objects/{fetch_014.phpt => fetch_op_skipped_prop_does_not_initialize.phpt} (83%) rename Zend/tests/lazy_objects/{fetch_010.phpt => fetch_ref_initializes.phpt} (76%) rename Zend/tests/lazy_objects/{fetch_015.phpt => fetch_ref_skipped_prop_does_not_initialize.phpt} (83%) rename Zend/tests/lazy_objects/{fetch_013.phpt => fetch_skipped_prop_does_not_initialize.phpt} (83%) rename Zend/tests/lazy_objects/{013.phpt => final_classes_can_be_initialized_lazily.phpt} (75%) rename Zend/tests/lazy_objects/{feedback_002.phpt => gc_006.phpt} (95%) rename Zend/tests/lazy_objects/{object_with_ast_const_001.phpt => init_ast_const.phpt} (100%) rename Zend/tests/lazy_objects/{object_with_ast_const_002.phpt => init_ast_const_failure.phpt} (100%) rename Zend/tests/lazy_objects/{init_exception_001.phpt => init_exception_leaves_object_lazy.phpt} (62%) rename Zend/tests/lazy_objects/{init_exception_002.phpt => init_exception_reverts_initializer_changes.phpt} (66%) rename Zend/tests/lazy_objects/{init_exception_005.phpt => init_exception_reverts_initializer_changes_dyn_props.phpt} (68%) rename Zend/tests/lazy_objects/{init_exception_006.phpt => init_exception_reverts_initializer_changes_dyn_props_and_ht.phpt} (70%) rename Zend/tests/lazy_objects/{feedback_005.phpt => init_exception_reverts_initializer_changes_nested.phpt} (91%) rename Zend/tests/lazy_objects/{init_exception_012.phpt => init_exception_reverts_initializer_changes_overridden_prop.phpt} (68%) rename Zend/tests/lazy_objects/{init_exception_003.phpt => init_exception_reverts_initializer_changes_props_ht.phpt} (69%) rename Zend/tests/lazy_objects/{init_exception_009.phpt => init_exception_reverts_initializer_changes_props_ht_ref.phpt} (73%) rename Zend/tests/lazy_objects/{024.phpt => init_fatal.phpt} (85%) rename Zend/tests/lazy_objects/{init_exception_010.phpt => init_handles_ref_source_types.phpt} (76%) rename Zend/tests/lazy_objects/{init_exception_011.phpt => init_handles_ref_source_types_exception.phpt} (81%) rename Zend/tests/lazy_objects/{ghost_002.phpt => init_may_leave_props_uninit.phpt} (74%) rename Zend/tests/lazy_objects/{feedback_004.phpt => init_preserves_identity.phpt} (90%) rename Zend/tests/lazy_objects/{feedback_003.phpt => init_preserves_proxy_class.phpt} (84%) rename Zend/tests/lazy_objects/{ghost_001.phpt => init_sets_prop_default_values.phpt} (72%) rename Zend/tests/lazy_objects/{012.phpt => init_trigger_array_cast.phpt} (71%) rename Zend/tests/lazy_objects/{027.phpt => init_trigger_debug_zval_dump.phpt} (100%) rename Zend/tests/lazy_objects/{006.phpt => init_trigger_foreach.phpt} (69%) rename Zend/tests/lazy_objects/{019.phpt => init_trigger_get_mangled_object_vars.phpt} (73%) rename Zend/tests/lazy_objects/{011.phpt => init_trigger_get_object_vars.phpt} (73%) rename Zend/tests/lazy_objects/{010.phpt => init_trigger_json_encode.phpt} (67%) rename Zend/tests/lazy_objects/{reflection_to_string_does_not_init.phpt => init_trigger_reflection_object_toString.phpt} (70%) rename Zend/tests/lazy_objects/{009.phpt => init_trigger_serialize.phpt} (68%) rename Zend/tests/lazy_objects/{007.phpt => init_trigger_var_dump.phpt} (95%) rename Zend/tests/lazy_objects/{025.phpt => init_trigger_var_dump_debug_info_001.phpt} (68%) rename Zend/tests/lazy_objects/{026.phpt => init_trigger_var_dump_debug_info_002.phpt} (70%) rename Zend/tests/lazy_objects/{008.phpt => init_trigger_var_export.phpt} (68%) rename Zend/tests/lazy_objects/{initialize_001.phpt => initializeLazyObject.phpt} (72%) rename Zend/tests/lazy_objects/{initialize_005.phpt => initializeLazyObject_error.phpt} (72%) rename Zend/tests/lazy_objects/{initialize_002.phpt => initializeLazyObject_noop_on_initialized_object.phpt} (67%) rename Zend/tests/lazy_objects/{005.phpt => initializer_must_return_the_right_type.phpt} (90%) create mode 100644 Zend/tests/lazy_objects/isUninitializedLazyObject.phpt delete mode 100644 Zend/tests/lazy_objects/is_initialized_001.phpt delete mode 100644 Zend/tests/lazy_objects/is_uninitialized_lazy_object.phpt rename Zend/tests/lazy_objects/{isset_002.phpt => isset_hooked_may_initialize.phpt} (75%) rename Zend/tests/lazy_objects/{isset_003.phpt => isset_hooked_may_not_initialize.phpt} (71%) rename Zend/tests/lazy_objects/{isset_001.phpt => isset_initializes.phpt} (78%) rename Zend/tests/lazy_objects/{mark_as_initialized_001.phpt => markLazyObjectAsInitialized.phpt} (76%) delete mode 100644 Zend/tests/lazy_objects/new_instance_lazy_001.phpt delete mode 100644 Zend/tests/lazy_objects/new_instance_lazy_002.phpt delete mode 100644 Zend/tests/lazy_objects/new_instance_lazy_003.phpt delete mode 100644 Zend/tests/lazy_objects/new_instance_lazy_004.phpt delete mode 100644 Zend/tests/lazy_objects/new_instance_lazy_005.phpt rename Zend/tests/lazy_objects/{realize_001.phpt => realize.phpt} (86%) rename Zend/tests/lazy_objects/{realize_003.phpt => realize_no_props.phpt} (100%) rename Zend/tests/lazy_objects/{props_of_proxy_must_not_be_lazy_004.phpt => realize_proxy_overridden.phpt} (85%) rename Zend/tests/lazy_objects/{realize_002.phpt => realize_skipped.phpt} (86%) rename Zend/tests/lazy_objects/{make_lazy_already_exception.phpt => reset_as_lazy_already_exception.phpt} (56%) rename Zend/tests/lazy_objects/{make_lazy_destructor_001.phpt => reset_as_lazy_calls_destructor.phpt} (78%) rename Zend/tests/lazy_objects/{021.phpt => reset_as_lazy_deletes_reference_source_type.phpt} (85%) rename Zend/tests/lazy_objects/{make_lazy_destructor_003.phpt => reset_as_lazy_destructor_exception.phpt} (81%) rename Zend/tests/lazy_objects/{feedback_008.phpt => reset_as_lazy_initialized_proxy.phpt} (93%) rename Zend/tests/lazy_objects/{feedback_001.phpt => reset_as_lazy_may_call_nested_destructors.phpt} (90%) rename Zend/tests/lazy_objects/{make_lazy_destructor_002.phpt => reset_as_lazy_may_skip_destructor.phpt} (76%) rename Zend/tests/lazy_objects/{reset_readonly_001.phpt => reset_as_lazy_readonly.phpt} (95%) rename Zend/tests/lazy_objects/{feedback_009.phpt => reset_as_lazy_real_instance.phpt} (88%) rename Zend/tests/lazy_objects/{020.phpt => reset_as_lazy_resets_dynamic_props.phpt} (84%) rename Zend/tests/lazy_objects/{ => rfc}/rfc_example_001.phpt (100%) rename Zend/tests/lazy_objects/{ => rfc}/rfc_example_002.phpt (100%) rename Zend/tests/lazy_objects/{ => rfc}/rfc_example_003.phpt (100%) rename Zend/tests/lazy_objects/{ => rfc}/rfc_example_004.phpt (100%) rename Zend/tests/lazy_objects/{ => rfc}/rfc_example_005.phpt (100%) rename Zend/tests/lazy_objects/{ => rfc}/rfc_example_006.phpt (100%) rename Zend/tests/lazy_objects/{ => rfc}/rfc_example_007.phpt (100%) rename Zend/tests/lazy_objects/{ => rfc}/rfc_example_008.phpt (100%) rename Zend/tests/lazy_objects/{ => rfc}/rfc_example_009.phpt (100%) rename Zend/tests/lazy_objects/{ => rfc}/rfc_example_010.phpt (100%) rename Zend/tests/lazy_objects/{ => rfc}/rfc_example_011.phpt (100%) rename Zend/tests/lazy_objects/{ => rfc}/rfc_example_012.phpt (100%) rename Zend/tests/lazy_objects/{serialize_006.phpt => serialize___serialize_may_initialize.phpt} (69%) rename Zend/tests/lazy_objects/{serialize_005.phpt => serialize___serialize_may_not_initialize.phpt} (62%) rename Zend/tests/lazy_objects/{serialize_007.phpt => serialize___sleep_initializes.phpt} (74%) rename Zend/tests/lazy_objects/{serialize_008.phpt => serialize___sleep_skip_flag.phpt} (74%) rename Zend/tests/lazy_objects/{serialize_009.phpt => serialize___sleep_skip_flag_may_initialize.phpt} (72%) rename Zend/tests/lazy_objects/{serialize_010.phpt => serialize_hook.phpt} (73%) rename Zend/tests/lazy_objects/{serialize_001.phpt => serialize_initializes.phpt} (70%) rename Zend/tests/lazy_objects/{serialize_002.phpt => serialize_props_ht.phpt} (72%) rename Zend/tests/lazy_objects/{serialize_003.phpt => serialize_skip_flag.phpt} (75%) rename Zend/tests/lazy_objects/{serialize_004.phpt => serialize_skip_flag_props_ht.phpt} (77%) rename Zend/tests/lazy_objects/{set_raw_value_001.phpt => setRawValueWithoutLazyInitialization.phpt} (100%) rename Zend/tests/lazy_objects/{skip_initialization_009.phpt => setRawValueWithoutLazyInitialization_exception.phpt} (100%) rename Zend/tests/lazy_objects/{set_raw_value_007.phpt => setRawValueWithoutLazyInitialization_initialized.phpt} (100%) rename Zend/tests/lazy_objects/{set_raw_value_008.phpt => setRawValueWithoutLazyInitialization_no_dynamic_prop.phpt} (100%) rename Zend/tests/lazy_objects/{set_raw_value_009.phpt => setRawValueWithoutLazyInitialization_readonly.phpt} (100%) rename Zend/tests/lazy_objects/{skip_initialization_008.phpt => setRawValueWithoutLazyInitialization_readonly_variant.phpt} (100%) rename Zend/tests/lazy_objects/{set_raw_value_003.phpt => setRawValueWithoutLazyInitialization_realize.phpt} (100%) rename Zend/tests/lazy_objects/{set_raw_value_006.phpt => setRawValueWithoutLazyInitialization_side_effect_destruct.phpt} (100%) rename Zend/tests/lazy_objects/{set_raw_value_005.phpt => setRawValueWithoutLazyInitialization_side_effect_toString.phpt} (100%) rename Zend/tests/lazy_objects/{set_raw_value_004.phpt => setRawValueWithoutLazyInitialization_skips___set.phpt} (100%) rename Zend/tests/lazy_objects/{set_raw_value_002.phpt => setRawValueWithoutLazyInitialization_skips_hook.phpt} (100%) rename Zend/tests/lazy_objects/{reflection_lazy_object_skip_property_001.phpt => skipLazyInitialization.phpt} (98%) rename Zend/tests/lazy_objects/{skip_initialization_001.phpt => skipLazyInitialization_default.phpt} (100%) rename Zend/tests/lazy_objects/{skip_initialization_006.phpt => skipLazyInitialization_initialized_object.phpt} (100%) rename Zend/tests/lazy_objects/{skip_initialization_010.phpt => skipLazyInitialization_no_dynamic_prop.phpt} (100%) rename Zend/tests/lazy_objects/{skip_initialization_007.phpt => skipLazyInitialization_readonly.phpt} (100%) rename Zend/tests/lazy_objects/{skip_initialization_003.phpt => skipLazyInitialization_realize.phpt} (100%) rename Zend/tests/lazy_objects/{skip_initialization_004.phpt => skipLazyInitialization_skips___set.phpt} (100%) rename Zend/tests/lazy_objects/{skip_initialization_002.phpt => skipLazyInitialization_skips_hooks.phpt} (100%) rename Zend/tests/lazy_objects/{skip_initialization_005.phpt => skipLazyInitialization_skips_non_lazy_prop.phpt} (100%) rename Zend/tests/lazy_objects/{014.phpt => support_no_internal_classes.phpt} (66%) rename Zend/tests/lazy_objects/{015.phpt => support_no_internal_sub_classes.phpt} (70%) rename Zend/tests/lazy_objects/{004.phpt => support_readonly_class.phpt} (74%) rename Zend/tests/lazy_objects/{003.phpt => support_readonly_prop.phpt} (74%) create mode 100644 Zend/tests/lazy_objects/support_stdClass.phpt create mode 100644 Zend/tests/lazy_objects/support_stdClass_sub_classes.phpt rename Zend/tests/lazy_objects/{unset_008.phpt => unset_defined_no_initialize.phpt} (75%) rename Zend/tests/lazy_objects/{unset_010.phpt => unset_hook.phpt} (79%) rename Zend/tests/lazy_objects/{unset_005.phpt => unset_magic_circular_may_initialize.phpt} (77%) rename Zend/tests/lazy_objects/{unset_004.phpt => unset_magic_may_initialize.phpt} (73%) rename Zend/tests/lazy_objects/{unset_003.phpt => unset_magic_may_not_initialize.phpt} (69%) rename Zend/tests/lazy_objects/{unset_009.phpt => unset_skipped_no_initialize.phpt} (78%) rename Zend/tests/lazy_objects/{unset_006.phpt => unset_undefined_dynamic_initializes.phpt} (76%) rename Zend/tests/lazy_objects/{unset_007.phpt => unset_undefined_dynamic_initializes_no_props_ht.phpt} (77%) rename Zend/tests/lazy_objects/{unset_001.phpt => unset_undefined_initializes.phpt} (77%) rename Zend/tests/lazy_objects/{write_002.phpt => write_dynamic_initializes.phpt} (74%) rename Zend/tests/lazy_objects/{write_005.phpt => write_initializer_exception.phpt} (69%) rename Zend/tests/lazy_objects/{write_001.phpt => write_initializes.phpt} (76%) rename Zend/tests/lazy_objects/{write_004.phpt => write_magic_circular_may_initialize.phpt} (76%) rename Zend/tests/lazy_objects/{write_003.phpt => write_magic_may_initialize.phpt} (76%) rename Zend/tests/lazy_objects/{write_006.phpt => write_skipped_no_initialize.phpt} (77%) diff --git a/Zend/tests/lazy_objects/016.phpt b/Zend/tests/lazy_objects/016.phpt deleted file mode 100644 index 5efd48bdebff1..0000000000000 --- a/Zend/tests/lazy_objects/016.phpt +++ /dev/null @@ -1,45 +0,0 @@ ---TEST-- -Lazy objects: destructor of lazy objets is not called if not initialized ---FILE-- -newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function () { - var_dump("initializer"); -}); -print "After makeLazy\n"; - -// Does not call destructor -$obj = null; - -print "# Virtual:\n"; - -print "In makeLazy\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function () { - var_dump("initializer"); -}); -print "After makeLazy\n"; - -// Does not call destructor -$obj = null; - ---EXPECT-- -# Ghost: -In makeLazy -string(13) "C::__destruct" -After makeLazy -# Virtual: -In makeLazy -string(13) "C::__destruct" -After makeLazy diff --git a/Zend/tests/lazy_objects/018.phpt b/Zend/tests/lazy_objects/018.phpt deleted file mode 100644 index 2ee1b6e2db630..0000000000000 --- a/Zend/tests/lazy_objects/018.phpt +++ /dev/null @@ -1,57 +0,0 @@ ---TEST-- -Lazy objects: exception during initializer leaves object uninitialized ---FILE-- -a); - } catch (Exception $e) { - printf("%s\n", $e->getMessage()); - } - var_dump((new ReflectionClass($obj))->isUninitializedLazyObject($obj)); - try { - var_dump($obj->a); - } catch (Exception $e) { - printf("%s\n", $e->getMessage()); - } - var_dump((new ReflectionClass($obj))->isUninitializedLazyObject($obj)); -} - -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function () { - var_dump("initializer"); - throw new \Exception('initializer exception'); -}); - -test('Ghost', $obj); - -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function () { - var_dump("initializer"); - throw new \Exception('initializer exception'); -}); - -test('Virtual', $obj); - ---EXPECT-- -# Ghost: -string(11) "initializer" -initializer exception -bool(true) -string(11) "initializer" -initializer exception -bool(true) -# Virtual: -string(11) "initializer" -initializer exception -bool(true) -string(11) "initializer" -initializer exception -bool(true) diff --git a/Zend/tests/lazy_objects/clone_002.phpt b/Zend/tests/lazy_objects/clone_calls___clone_once.phpt similarity index 100% rename from Zend/tests/lazy_objects/clone_002.phpt rename to Zend/tests/lazy_objects/clone_calls___clone_once.phpt diff --git a/Zend/tests/lazy_objects/clone_007.phpt b/Zend/tests/lazy_objects/clone_creates_object_with_independent_state_001.phpt similarity index 92% rename from Zend/tests/lazy_objects/clone_007.phpt rename to Zend/tests/lazy_objects/clone_creates_object_with_independent_state_001.phpt index 9a350e6f01cd8..10aab3da023b3 100644 --- a/Zend/tests/lazy_objects/clone_007.phpt +++ b/Zend/tests/lazy_objects/clone_creates_object_with_independent_state_001.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: clone semantics +Lazy objects: clone is independant of the original object --FILE-- ==DONE== --EXPECT-- +string(1) "B" +string(1) "B" ==DONE== diff --git a/Zend/tests/lazy_objects/017.phpt b/Zend/tests/lazy_objects/dtor_called_if_init.phpt similarity index 66% rename from Zend/tests/lazy_objects/017.phpt rename to Zend/tests/lazy_objects/dtor_called_if_init.phpt index e5ebc8aa50ad5..4002a66a13c36 100644 --- a/Zend/tests/lazy_objects/017.phpt +++ b/Zend/tests/lazy_objects/dtor_called_if_init.phpt @@ -12,11 +12,12 @@ class C { } function ghost() { + $reflector = new ReflectionClass(C::class); + print "# Ghost:\n"; print "In makeLazy\n"; - $obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); - (new ReflectionClass($obj))->resetAsLazyGhost($obj, function () { + $obj = $reflector->newLazyGhost(function () { var_dump("initializer"); }); print "After makeLazy\n"; @@ -25,11 +26,12 @@ function ghost() { } function virtual() { + $reflector = new ReflectionClass(C::class); + print "# Virtual:\n"; print "In makeLazy\n"; - $obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); - (new ReflectionClass($obj))->resetAsLazyProxy($obj, function () { + $obj = $reflector->newLazyProxy(function () { var_dump("initializer"); return new C(); }); @@ -44,11 +46,6 @@ virtual(); --EXPECTF-- # Ghost: In makeLazy -string(13) "C::__destruct" -object(C)#%d (1) { - ["a"]=> - int(1) -} After makeLazy string(11) "initializer" int(1) @@ -59,11 +56,6 @@ object(C)#%d (1) { } # Virtual: In makeLazy -string(13) "C::__destruct" -object(C)#%d (1) { - ["a"]=> - int(1) -} After makeLazy string(11) "initializer" int(1) diff --git a/Zend/tests/lazy_objects/dtor_not_called_if_not_init.phpt b/Zend/tests/lazy_objects/dtor_not_called_if_not_init.phpt new file mode 100644 index 0000000000000..17855588ec1fc --- /dev/null +++ b/Zend/tests/lazy_objects/dtor_not_called_if_not_init.phpt @@ -0,0 +1,43 @@ +--TEST-- +Lazy objects: destructor of lazy objets is not called if not initialized +--FILE-- +newLazyGhost(function () { + var_dump("initializer"); +}); +print "After newLazyGhost\n"; + +// Does not call destructor +$obj = null; + +print "# Virtual:\n"; + +print "In newLazyProxy\n"; +$obj = $reflector->newLazyProxy(function () { + var_dump("initializer"); +}); +print "After newLazyGhost\n"; + +// Does not call destructor +$obj = null; + +--EXPECT-- +# Ghost: +In newLazyGhost +After newLazyGhost +# Virtual: +In newLazyProxy +After newLazyGhost diff --git a/Zend/tests/lazy_objects/feedback_006.phpt b/Zend/tests/lazy_objects/feedback_006.phpt deleted file mode 100644 index 64d1ae00938e3..0000000000000 --- a/Zend/tests/lazy_objects/feedback_006.phpt +++ /dev/null @@ -1,29 +0,0 @@ ---TEST-- -Lazy objects: feedback 006 ---FILE-- -foo; - } -} - -$r = new ReflectionClass(B::class); -$obj = $r->newLazyProxy(function ($obj) { - return new A(); -}); - -try { - $obj->getFoo(); -} catch (\Throwable $e) { - printf("%s: %s\n", $e::class, $e->getMessage()); -} - -?> ---EXPECT-- -TypeError: The real instance class A is not compatible with the proxy class B. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor or __clone methods. diff --git a/Zend/tests/lazy_objects/fetch_008.phpt b/Zend/tests/lazy_objects/fetch_coalesce_initializes.phpt similarity index 76% rename from Zend/tests/lazy_objects/fetch_008.phpt rename to Zend/tests/lazy_objects/fetch_coalesce_initializes.phpt index 1a87364e8ded5..832fc7f4f64bd 100644 --- a/Zend/tests/lazy_objects/fetch_008.phpt +++ b/Zend/tests/lazy_objects/fetch_coalesce_initializes.phpt @@ -18,16 +18,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/fetch_009.phpt b/Zend/tests/lazy_objects/fetch_coalesce_non_existing_initializes.phpt similarity index 76% rename from Zend/tests/lazy_objects/fetch_009.phpt rename to Zend/tests/lazy_objects/fetch_coalesce_non_existing_initializes.phpt index d4316320c6e9d..5ed1e27133618 100644 --- a/Zend/tests/lazy_objects/fetch_009.phpt +++ b/Zend/tests/lazy_objects/fetch_coalesce_non_existing_initializes.phpt @@ -18,16 +18,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/fetch_001.phpt b/Zend/tests/lazy_objects/fetch_declared_prop_initializes.phpt similarity index 77% rename from Zend/tests/lazy_objects/fetch_001.phpt rename to Zend/tests/lazy_objects/fetch_declared_prop_initializes.phpt index d89cba11d4481..7b055c060ae3d 100644 --- a/Zend/tests/lazy_objects/fetch_001.phpt +++ b/Zend/tests/lazy_objects/fetch_declared_prop_initializes.phpt @@ -22,16 +22,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(1); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(1); }); diff --git a/Zend/tests/lazy_objects/fetch_002.phpt b/Zend/tests/lazy_objects/fetch_dynamic_prop_initializes.phpt similarity index 77% rename from Zend/tests/lazy_objects/fetch_002.phpt rename to Zend/tests/lazy_objects/fetch_dynamic_prop_initializes.phpt index fda287265948e..dc4d92d2965dd 100644 --- a/Zend/tests/lazy_objects/fetch_002.phpt +++ b/Zend/tests/lazy_objects/fetch_dynamic_prop_initializes.phpt @@ -19,16 +19,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/fetch_016.phpt b/Zend/tests/lazy_objects/fetch_hook_may_not_initialize.phpt similarity index 75% rename from Zend/tests/lazy_objects/fetch_016.phpt rename to Zend/tests/lazy_objects/fetch_hook_may_not_initialize.phpt index 5e27cb77a5abc..b87134fff0934 100644 --- a/Zend/tests/lazy_objects/fetch_016.phpt +++ b/Zend/tests/lazy_objects/fetch_hook_may_not_initialize.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: hooked property fetch may initialize object +Lazy objects: hooked property fetch does not initialize object if hook does not observe object state --FILE-- newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(1); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(1); }); diff --git a/Zend/tests/lazy_objects/fetch_017.phpt b/Zend/tests/lazy_objects/fetch_hook_virtual_may_initialize.phpt similarity index 79% rename from Zend/tests/lazy_objects/fetch_017.phpt rename to Zend/tests/lazy_objects/fetch_hook_virtual_may_initialize.phpt index 88d40a59101ac..a81f52795966e 100644 --- a/Zend/tests/lazy_objects/fetch_017.phpt +++ b/Zend/tests/lazy_objects/fetch_hook_virtual_may_initialize.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: virtual hooked property fetch may initialize object +Lazy objects: virtual hooked property fetch may initialize object if hook observes object state --FILE-- newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(1); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(1); }); diff --git a/Zend/tests/lazy_objects/fetch_018.phpt b/Zend/tests/lazy_objects/fetch_hook_virtual_may_not_initialize.phpt similarity index 69% rename from Zend/tests/lazy_objects/fetch_018.phpt rename to Zend/tests/lazy_objects/fetch_hook_virtual_may_not_initialize.phpt index c66d657dfcd0f..cd9a1d837c95e 100644 --- a/Zend/tests/lazy_objects/fetch_018.phpt +++ b/Zend/tests/lazy_objects/fetch_hook_virtual_may_not_initialize.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: virtual hooked property fetch may not initialize object +Lazy objects: virtual hooked property fetch does not initialize object if hook does not observe object state --FILE-- newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(1); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(1); }); diff --git a/Zend/tests/lazy_objects/fetch_006.phpt b/Zend/tests/lazy_objects/fetch_magic_prop_may_initialize.phpt similarity index 72% rename from Zend/tests/lazy_objects/fetch_006.phpt rename to Zend/tests/lazy_objects/fetch_magic_prop_may_initialize.phpt index ecf5ab123b4bf..cff2e62d1bb47 100644 --- a/Zend/tests/lazy_objects/fetch_006.phpt +++ b/Zend/tests/lazy_objects/fetch_magic_prop_may_initialize.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: magic property fetch may initialize object +Lazy objects: magic property fetch initializes object if magic method observes object state --FILE-- newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/fetch_005.phpt b/Zend/tests/lazy_objects/fetch_magic_prop_may_not_initialize.phpt similarity index 70% rename from Zend/tests/lazy_objects/fetch_005.phpt rename to Zend/tests/lazy_objects/fetch_magic_prop_may_not_initialize.phpt index 11b8d463ced95..bc362abf02831 100644 --- a/Zend/tests/lazy_objects/fetch_005.phpt +++ b/Zend/tests/lazy_objects/fetch_magic_prop_may_not_initialize.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: magic property fetch may not initialize object +Lazy objects: magic property fetch does not not initialize object if magic method does not observe object state --FILE-- newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/fetch_007.phpt b/Zend/tests/lazy_objects/fetch_magic_prop_recursive_may_initialize.phpt similarity index 74% rename from Zend/tests/lazy_objects/fetch_007.phpt rename to Zend/tests/lazy_objects/fetch_magic_prop_recursive_may_initialize.phpt index abdb8212a11b2..c1c9dcb1cfe42 100644 --- a/Zend/tests/lazy_objects/fetch_007.phpt +++ b/Zend/tests/lazy_objects/fetch_magic_prop_recursive_may_initialize.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: recursive magic property fetch may initialize object +Lazy objects: recursive magic property fetch initializes object if magic method observes object state --FILE-- newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/fetch_011.phpt b/Zend/tests/lazy_objects/fetch_op_dynamic_error.phpt similarity index 76% rename from Zend/tests/lazy_objects/fetch_011.phpt rename to Zend/tests/lazy_objects/fetch_op_dynamic_error.phpt index 077a11a2f60ff..1efd76071224a 100644 --- a/Zend/tests/lazy_objects/fetch_011.phpt +++ b/Zend/tests/lazy_objects/fetch_op_dynamic_error.phpt @@ -24,16 +24,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { throw new Error("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { throw new Error("initializer"); }); diff --git a/Zend/tests/lazy_objects/fetch_004.phpt b/Zend/tests/lazy_objects/fetch_op_dynamic_prop_initializes.phpt similarity index 77% rename from Zend/tests/lazy_objects/fetch_004.phpt rename to Zend/tests/lazy_objects/fetch_op_dynamic_prop_initializes.phpt index 892850fed5f0f..e52e3c8cdf184 100644 --- a/Zend/tests/lazy_objects/fetch_004.phpt +++ b/Zend/tests/lazy_objects/fetch_op_dynamic_prop_initializes.phpt @@ -19,16 +19,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/fetch_012.phpt b/Zend/tests/lazy_objects/fetch_op_error.phpt similarity index 75% rename from Zend/tests/lazy_objects/fetch_012.phpt rename to Zend/tests/lazy_objects/fetch_op_error.phpt index 8c3b591350f80..7e04d3593d527 100644 --- a/Zend/tests/lazy_objects/fetch_012.phpt +++ b/Zend/tests/lazy_objects/fetch_op_error.phpt @@ -25,15 +25,15 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { throw new Error("initializer"); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { throw new Error("initializer"); }); diff --git a/Zend/tests/lazy_objects/fetch_003.phpt b/Zend/tests/lazy_objects/fetch_op_initializes.phpt similarity index 76% rename from Zend/tests/lazy_objects/fetch_003.phpt rename to Zend/tests/lazy_objects/fetch_op_initializes.phpt index d24af36221a0f..1731f7004fc75 100644 --- a/Zend/tests/lazy_objects/fetch_003.phpt +++ b/Zend/tests/lazy_objects/fetch_op_initializes.phpt @@ -19,16 +19,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/fetch_014.phpt b/Zend/tests/lazy_objects/fetch_op_skipped_prop_does_not_initialize.phpt similarity index 83% rename from Zend/tests/lazy_objects/fetch_014.phpt rename to Zend/tests/lazy_objects/fetch_op_skipped_prop_does_not_initialize.phpt index 0320a073039b6..f152366b12ca1 100644 --- a/Zend/tests/lazy_objects/fetch_014.phpt +++ b/Zend/tests/lazy_objects/fetch_op_skipped_prop_does_not_initialize.phpt @@ -32,16 +32,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new c(); }); diff --git a/Zend/tests/lazy_objects/fetch_010.phpt b/Zend/tests/lazy_objects/fetch_ref_initializes.phpt similarity index 76% rename from Zend/tests/lazy_objects/fetch_010.phpt rename to Zend/tests/lazy_objects/fetch_ref_initializes.phpt index 6fb013c3ff1b2..6c7c28cee5084 100644 --- a/Zend/tests/lazy_objects/fetch_010.phpt +++ b/Zend/tests/lazy_objects/fetch_ref_initializes.phpt @@ -19,16 +19,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/fetch_015.phpt b/Zend/tests/lazy_objects/fetch_ref_skipped_prop_does_not_initialize.phpt similarity index 83% rename from Zend/tests/lazy_objects/fetch_015.phpt rename to Zend/tests/lazy_objects/fetch_ref_skipped_prop_does_not_initialize.phpt index c4c77a679329b..26a820cbb092a 100644 --- a/Zend/tests/lazy_objects/fetch_015.phpt +++ b/Zend/tests/lazy_objects/fetch_ref_skipped_prop_does_not_initialize.phpt @@ -27,16 +27,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/fetch_013.phpt b/Zend/tests/lazy_objects/fetch_skipped_prop_does_not_initialize.phpt similarity index 83% rename from Zend/tests/lazy_objects/fetch_013.phpt rename to Zend/tests/lazy_objects/fetch_skipped_prop_does_not_initialize.phpt index 96faaf3f19d10..f210e8b05aaa7 100644 --- a/Zend/tests/lazy_objects/fetch_013.phpt +++ b/Zend/tests/lazy_objects/fetch_skipped_prop_does_not_initialize.phpt @@ -34,16 +34,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(1); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(1); }); diff --git a/Zend/tests/lazy_objects/013.phpt b/Zend/tests/lazy_objects/final_classes_can_be_initialized_lazily.phpt similarity index 75% rename from Zend/tests/lazy_objects/013.phpt rename to Zend/tests/lazy_objects/final_classes_can_be_initialized_lazily.phpt index 8e92692169bc1..42a5177f91125 100644 --- a/Zend/tests/lazy_objects/013.phpt +++ b/Zend/tests/lazy_objects/final_classes_can_be_initialized_lazily.phpt @@ -11,10 +11,11 @@ final class C { } } +$reflector = new ReflectionClass(C::class); + print "# Ghost:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); @@ -25,8 +26,7 @@ var_dump($obj); print "# Virtual:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/feedback_002.phpt b/Zend/tests/lazy_objects/gc_006.phpt similarity index 95% rename from Zend/tests/lazy_objects/feedback_002.phpt rename to Zend/tests/lazy_objects/gc_006.phpt index 76138e8656a75..e1002ffea7108 100644 --- a/Zend/tests/lazy_objects/feedback_002.phpt +++ b/Zend/tests/lazy_objects/gc_006.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: feedback 002 +Lazy objects: GC 006 --FILE-- initializeLazyObject($obj); + $reflector->initializeLazyObject($obj); } catch (Exception $e) { printf("%s\n", $e->getMessage()); } - printf("Is lazy: %d\n", (new ReflectionClass($obj))->isUninitializedLazyObject($obj)); + printf("Is lazy: %d\n", $reflector->isUninitializedLazyObject($obj)); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->a = 3; $obj->b = 4; @@ -30,8 +33,7 @@ $obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); $obj->a = 3; $obj->b = 4; diff --git a/Zend/tests/lazy_objects/init_exception_002.phpt b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes.phpt similarity index 66% rename from Zend/tests/lazy_objects/init_exception_002.phpt rename to Zend/tests/lazy_objects/init_exception_reverts_initializer_changes.phpt index e14a873b3f9cb..2bc098a8d19ee 100644 --- a/Zend/tests/lazy_objects/init_exception_002.phpt +++ b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes.phpt @@ -10,22 +10,25 @@ class C { } function test(string $name, object $obj) { + $reflector = new ReflectionClass(C::class); + printf("# %s:\n", $name); - (new ReflectionProperty($obj, 'c'))->setRawValueWithoutLazyInitialization($obj, 0); + (new ReflectionProperty(C::class, 'c'))->setRawValueWithoutLazyInitialization($obj, 0); try { - (new ReflectionClass($obj))->initializeLazyObject($obj); + $reflector->initializeLazyObject($obj); } catch (Exception $e) { printf("%s\n", $e->getMessage()); } var_dump($obj); - printf("Is lazy: %d\n", (new ReflectionClass($obj))->isUninitializedLazyObject($obj)); + printf("Is lazy: %d\n", $reflector->isUninitializedLazyObject($obj)); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->a = 3; $obj->b = 4; @@ -35,8 +38,7 @@ $obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); $obj->a = 3; $obj->b = 4; diff --git a/Zend/tests/lazy_objects/init_exception_005.phpt b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props.phpt similarity index 68% rename from Zend/tests/lazy_objects/init_exception_005.phpt rename to Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props.phpt index db5b6dabefb6d..ba91c973a11d0 100644 --- a/Zend/tests/lazy_objects/init_exception_005.phpt +++ b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props.phpt @@ -11,22 +11,25 @@ class C { } function test(string $name, object $obj) { + $reflector = new ReflectionClass(C::class); + printf("# %s:\n", $name); - (new ReflectionProperty($obj, 'c'))->setRawValueWithoutLazyInitialization($obj, 0); + (new ReflectionProperty(C::class, 'c'))->setRawValueWithoutLazyInitialization($obj, 0); try { - (new ReflectionClass($obj))->initializeLazyObject($obj); + $reflector->initializeLazyObject($obj); } catch (Exception $e) { printf("%s\n", $e->getMessage()); } var_dump($obj); - printf("Is lazy: %d\n", (new ReflectionClass($obj))->isUninitializedLazyObject($obj)); + printf("Is lazy: %d\n", $reflector->isUninitializedLazyObject($obj)); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->a = 3; $obj->b = 4; @@ -37,8 +40,7 @@ $obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); $obj->a = 3; $obj->b = 4; diff --git a/Zend/tests/lazy_objects/init_exception_006.phpt b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props_and_ht.phpt similarity index 70% rename from Zend/tests/lazy_objects/init_exception_006.phpt rename to Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props_and_ht.phpt index 28ff9331ceb20..7de4025dcee94 100644 --- a/Zend/tests/lazy_objects/init_exception_006.phpt +++ b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props_and_ht.phpt @@ -11,25 +11,28 @@ class C { } function test(string $name, object $obj) { + $reflector = new ReflectionClass(C::class); + printf("# %s:\n", $name); // Builds properties hashtable var_dump(get_mangled_object_vars($obj)); - (new ReflectionProperty($obj, 'c'))->setRawValueWithoutLazyInitialization($obj, 0); + (new ReflectionProperty(C::class, 'c'))->setRawValueWithoutLazyInitialization($obj, 0); try { - (new ReflectionClass($obj))->initializeLazyObject($obj); + $reflector->initializeLazyObject($obj); } catch (Exception $e) { printf("%s\n", $e->getMessage()); } var_dump($obj); - printf("Is lazy: %d\n", (new ReflectionClass($obj))->isUninitializedLazyObject($obj)); + printf("Is lazy: %d\n", $reflector->isUninitializedLazyObject($obj)); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->a = 3; $obj->b = 4; @@ -40,8 +43,7 @@ $obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); $obj->a = 3; $obj->b = 4; diff --git a/Zend/tests/lazy_objects/feedback_005.phpt b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_nested.phpt similarity index 91% rename from Zend/tests/lazy_objects/feedback_005.phpt rename to Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_nested.phpt index 83454e70a7c96..535f93e65f63f 100644 --- a/Zend/tests/lazy_objects/feedback_005.phpt +++ b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_nested.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: feedback 005 +Lazy objects: Initializer effects are reverted after exception (nested) --FILE-- getProperty('b')->skipLazyInitialization($obj); $i = 5; $obj->b = &$i; @@ -25,11 +26,12 @@ function test(string $name, object $obj) { printf("%s\n", $e->getMessage()); } - printf("Is lazy: %d\n", (new ReflectionClass($obj))->isUninitializedLazyObject($obj)); + printf("Is lazy: %d\n", $reflector->isUninitializedLazyObject($obj)); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->a = 3; $obj->b = 4; @@ -38,8 +40,7 @@ $obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); $obj->a = 3; $obj->b = 4; diff --git a/Zend/tests/lazy_objects/init_exception_003.phpt b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht.phpt similarity index 69% rename from Zend/tests/lazy_objects/init_exception_003.phpt rename to Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht.phpt index 26eabc8bf4204..081a4d2737f48 100644 --- a/Zend/tests/lazy_objects/init_exception_003.phpt +++ b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht.phpt @@ -10,25 +10,28 @@ class C { } function test(string $name, object $obj) { + $reflector = new ReflectionClass(C::class); + printf("# %s:\n", $name); - (new ReflectionProperty($obj, 'c'))->setRawValueWithoutLazyInitialization($obj, 0); + (new ReflectionProperty(C::class, 'c'))->setRawValueWithoutLazyInitialization($obj, 0); // Builds properties hashtable var_dump(get_mangled_object_vars($obj)); try { - (new ReflectionClass($obj))->initializeLazyObject($obj); + $reflector->initializeLazyObject($obj); } catch (Exception $e) { printf("%s\n", $e->getMessage()); } var_dump($obj); - printf("Is lazy: %d\n", (new ReflectionClass($obj))->isUninitializedLazyObject($obj)); + printf("Is lazy: %d\n", $reflector->isUninitializedLazyObject($obj)); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->a = 3; $obj->b = 4; @@ -38,8 +41,7 @@ $obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); $obj->a = 3; $obj->b = 4; diff --git a/Zend/tests/lazy_objects/init_exception_009.phpt b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht_ref.phpt similarity index 73% rename from Zend/tests/lazy_objects/init_exception_009.phpt rename to Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht_ref.phpt index ad6c4232214a6..f3d4285f55257 100644 --- a/Zend/tests/lazy_objects/init_exception_009.phpt +++ b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht_ref.phpt @@ -10,27 +10,30 @@ class C { } function test(string $name, object $obj) { + $reflector = new ReflectionClass(C::class); + printf("# %s:\n", $name); - (new ReflectionProperty($obj, 'c'))->setRawValueWithoutLazyInitialization($obj, 0); + (new ReflectionProperty(C::class, 'c'))->setRawValueWithoutLazyInitialization($obj, 0); // Builds properties hashtable var_dump(get_mangled_object_vars($obj)); try { - (new ReflectionClass($obj))->initializeLazyObject($obj); + $reflector->initializeLazyObject($obj); } catch (Exception $e) { printf("%s\n", $e->getMessage()); } var_dump($obj); - printf("Is lazy: %d\n", (new ReflectionClass($obj))->isUninitializedLazyObject($obj)); + printf("Is lazy: %d\n", $reflector->isUninitializedLazyObject($obj)); var_dump($table); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { global $table; var_dump("initializer"); $obj->a = 3; @@ -42,8 +45,7 @@ $obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { global $table; var_dump("initializer"); $obj->a = 3; diff --git a/Zend/tests/lazy_objects/024.phpt b/Zend/tests/lazy_objects/init_fatal.phpt similarity index 85% rename from Zend/tests/lazy_objects/024.phpt rename to Zend/tests/lazy_objects/init_fatal.phpt index 548088394a650..7f5e03c94b0fa 100644 --- a/Zend/tests/lazy_objects/024.phpt +++ b/Zend/tests/lazy_objects/init_fatal.phpt @@ -13,8 +13,7 @@ class C { } $reflector = new ReflectionClass(C::class); -$obj = $reflector->newInstanceWithoutConstructor(); -$reflector->resetAsLazyGhost($obj, function ($obj) { +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); diff --git a/Zend/tests/lazy_objects/init_exception_010.phpt b/Zend/tests/lazy_objects/init_handles_ref_source_types.phpt similarity index 76% rename from Zend/tests/lazy_objects/init_exception_010.phpt rename to Zend/tests/lazy_objects/init_handles_ref_source_types.phpt index 788d92ec6e6b5..1042131ec3165 100644 --- a/Zend/tests/lazy_objects/init_exception_010.phpt +++ b/Zend/tests/lazy_objects/init_handles_ref_source_types.phpt @@ -15,12 +15,13 @@ class C { } function test(string $name, object $obj) { + $reflector = new ReflectionClass(C::class); + printf("# %s:\n", $name); - $r = new ReflectionClass($obj); - $r->getProperty('a')->setRawValueWithoutLazyInitialization($obj, null); + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, null); $refA = &$obj->a; - $r->getProperty('b')->setRawValueWithoutLazyInitialization($obj, null); + $reflector->getProperty('b')->setRawValueWithoutLazyInitialization($obj, null); $refB = &$obj->b; var_dump($obj); @@ -41,19 +42,18 @@ function test(string $name, object $obj) { $refA = 1; $refB = 1; - } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -$r = (new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(null); }); diff --git a/Zend/tests/lazy_objects/init_exception_011.phpt b/Zend/tests/lazy_objects/init_handles_ref_source_types_exception.phpt similarity index 81% rename from Zend/tests/lazy_objects/init_exception_011.phpt rename to Zend/tests/lazy_objects/init_handles_ref_source_types_exception.phpt index de6c5ff5fd61e..d2caad0ccd84e 100644 --- a/Zend/tests/lazy_objects/init_exception_011.phpt +++ b/Zend/tests/lazy_objects/init_handles_ref_source_types_exception.phpt @@ -14,12 +14,13 @@ class C { } function test(string $name, object $obj) { + $reflector = new ReflectionClass(C::class); + printf("# %s:\n", $name); - $r = new ReflectionClass($obj); - $r->getProperty('a')->setRawValueWithoutLazyInitialization($obj, null); + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, null); $refA = &$obj->a; - $r->getProperty('b')->setRawValueWithoutLazyInitialization($obj, null); + $reflector->getProperty('b')->setRawValueWithoutLazyInitialization($obj, null); $refB = &$obj->b; var_dump($obj); @@ -56,16 +57,16 @@ function test(string $name, object $obj) { } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -$r = (new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(null); }); diff --git a/Zend/tests/lazy_objects/ghost_002.phpt b/Zend/tests/lazy_objects/init_may_leave_props_uninit.phpt similarity index 74% rename from Zend/tests/lazy_objects/ghost_002.phpt rename to Zend/tests/lazy_objects/init_may_leave_props_uninit.phpt index 8c818c035a841..954433918b92b 100644 --- a/Zend/tests/lazy_objects/ghost_002.phpt +++ b/Zend/tests/lazy_objects/init_may_leave_props_uninit.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: properties may be left uninitialized by the initializer +Lazy objects: properties with no default values are left uninitialized --FILE-- newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); diff --git a/Zend/tests/lazy_objects/feedback_004.phpt b/Zend/tests/lazy_objects/init_preserves_identity.phpt similarity index 90% rename from Zend/tests/lazy_objects/feedback_004.phpt rename to Zend/tests/lazy_objects/init_preserves_identity.phpt index fb6d2e31fe0e0..7ef197d43112a 100644 --- a/Zend/tests/lazy_objects/feedback_004.phpt +++ b/Zend/tests/lazy_objects/init_preserves_identity.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: feedback 004 +Lazy objects: initialization of proxy does not change object id --FILE-- newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); var_dump($obj); $obj->__construct(); diff --git a/Zend/tests/lazy_objects/012.phpt b/Zend/tests/lazy_objects/init_trigger_array_cast.phpt similarity index 71% rename from Zend/tests/lazy_objects/012.phpt rename to Zend/tests/lazy_objects/init_trigger_array_cast.phpt index ab8e5c5c3fcbe..e58e1cbbd775a 100644 --- a/Zend/tests/lazy_objects/012.phpt +++ b/Zend/tests/lazy_objects/init_trigger_array_cast.phpt @@ -11,10 +11,11 @@ class C { } } +$reflector = new ReflectionClass(C::class); + print "# Ghost:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); @@ -26,8 +27,7 @@ var_dump((array)$obj); print "# Virtual:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/027.phpt b/Zend/tests/lazy_objects/init_trigger_debug_zval_dump.phpt similarity index 100% rename from Zend/tests/lazy_objects/027.phpt rename to Zend/tests/lazy_objects/init_trigger_debug_zval_dump.phpt diff --git a/Zend/tests/lazy_objects/006.phpt b/Zend/tests/lazy_objects/init_trigger_foreach.phpt similarity index 69% rename from Zend/tests/lazy_objects/006.phpt rename to Zend/tests/lazy_objects/init_trigger_foreach.phpt index 43211fa38e117..dd5c8b6291433 100644 --- a/Zend/tests/lazy_objects/006.phpt +++ b/Zend/tests/lazy_objects/init_trigger_foreach.phpt @@ -11,10 +11,11 @@ class C { } } +$reflector = new ReflectionClass(C::class); + print "# Ghost:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); @@ -25,8 +26,7 @@ foreach ($obj as $prop => $value) { print "# Virtual:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/019.phpt b/Zend/tests/lazy_objects/init_trigger_get_mangled_object_vars.phpt similarity index 73% rename from Zend/tests/lazy_objects/019.phpt rename to Zend/tests/lazy_objects/init_trigger_get_mangled_object_vars.phpt index 819421f60afd4..ccac68990820c 100644 --- a/Zend/tests/lazy_objects/019.phpt +++ b/Zend/tests/lazy_objects/init_trigger_get_mangled_object_vars.phpt @@ -20,16 +20,16 @@ function test(string $name, object $obj) { var_dump(get_mangled_object_vars($obj)); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/011.phpt b/Zend/tests/lazy_objects/init_trigger_get_object_vars.phpt similarity index 73% rename from Zend/tests/lazy_objects/011.phpt rename to Zend/tests/lazy_objects/init_trigger_get_object_vars.phpt index 3636a53d19831..19b2ad936299c 100644 --- a/Zend/tests/lazy_objects/011.phpt +++ b/Zend/tests/lazy_objects/init_trigger_get_object_vars.phpt @@ -11,10 +11,11 @@ class C { } } +$reflector = new ReflectionClass(C::class); + print "# Ghost:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); @@ -26,8 +27,7 @@ var_dump(get_object_vars($obj)); print "# Virtual:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/010.phpt b/Zend/tests/lazy_objects/init_trigger_json_encode.phpt similarity index 67% rename from Zend/tests/lazy_objects/010.phpt rename to Zend/tests/lazy_objects/init_trigger_json_encode.phpt index ad996a5a21191..02b2331fcdb38 100644 --- a/Zend/tests/lazy_objects/010.phpt +++ b/Zend/tests/lazy_objects/init_trigger_json_encode.phpt @@ -11,10 +11,11 @@ class C { } } +$reflector = new ReflectionClass(C::class); + print "# Ghost:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); @@ -23,8 +24,7 @@ var_dump(json_encode($obj)); print "# Virtual:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/reflection_to_string_does_not_init.phpt b/Zend/tests/lazy_objects/init_trigger_reflection_object_toString.phpt similarity index 70% rename from Zend/tests/lazy_objects/reflection_to_string_does_not_init.phpt rename to Zend/tests/lazy_objects/init_trigger_reflection_object_toString.phpt index 0b22d564baa76..dbf16348d83b7 100644 --- a/Zend/tests/lazy_objects/reflection_to_string_does_not_init.phpt +++ b/Zend/tests/lazy_objects/init_trigger_reflection_object_toString.phpt @@ -20,16 +20,16 @@ function test(string $name, object $obj) { var_dump(!(new ReflectionClass($obj))->isUninitializedLazyObject($obj)); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/009.phpt b/Zend/tests/lazy_objects/init_trigger_serialize.phpt similarity index 68% rename from Zend/tests/lazy_objects/009.phpt rename to Zend/tests/lazy_objects/init_trigger_serialize.phpt index 7f1263a50af70..a14edded5ae16 100644 --- a/Zend/tests/lazy_objects/009.phpt +++ b/Zend/tests/lazy_objects/init_trigger_serialize.phpt @@ -11,10 +11,11 @@ class C { } } +$reflector = new ReflectionClass(C::class); + print "# Ghost:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); @@ -23,8 +24,7 @@ var_dump(serialize($obj)); print "# Virtual:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/007.phpt b/Zend/tests/lazy_objects/init_trigger_var_dump.phpt similarity index 95% rename from Zend/tests/lazy_objects/007.phpt rename to Zend/tests/lazy_objects/init_trigger_var_dump.phpt index 6dfdf1457f4cf..30ece89208fa6 100644 --- a/Zend/tests/lazy_objects/007.phpt +++ b/Zend/tests/lazy_objects/init_trigger_var_dump.phpt @@ -26,7 +26,6 @@ var_dump($obj); print "# Virtual:\n"; -$reflector = new ReflectionClass(C::class); $obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); diff --git a/Zend/tests/lazy_objects/025.phpt b/Zend/tests/lazy_objects/init_trigger_var_dump_debug_info_001.phpt similarity index 68% rename from Zend/tests/lazy_objects/025.phpt rename to Zend/tests/lazy_objects/init_trigger_var_dump_debug_info_001.phpt index 3f101dc5a2060..f752815f8e8b3 100644 --- a/Zend/tests/lazy_objects/025.phpt +++ b/Zend/tests/lazy_objects/init_trigger_var_dump_debug_info_001.phpt @@ -15,23 +15,25 @@ class C { } function test(string $name, object $obj) { + $reflector = new ReflectionClass(C::class); + printf("# %s\n", $name); var_dump($obj); printf("Initialized:\n"); - var_dump(!(new ReflectionClass($obj))->isUninitializedLazyObject($obj)); + var_dump(!$reflector->isUninitializedLazyObject($obj)); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/026.phpt b/Zend/tests/lazy_objects/init_trigger_var_dump_debug_info_002.phpt similarity index 70% rename from Zend/tests/lazy_objects/026.phpt rename to Zend/tests/lazy_objects/init_trigger_var_dump_debug_info_002.phpt index aea4a5003cf0c..7ec224e7b6b59 100644 --- a/Zend/tests/lazy_objects/026.phpt +++ b/Zend/tests/lazy_objects/init_trigger_var_dump_debug_info_002.phpt @@ -15,23 +15,24 @@ class C { } function test(string $name, object $obj) { + $reflector = new ReflectionClass(C::class); printf("# %s\n", $name); var_dump($obj); printf("Initialized:\n"); - var_dump(!(new ReflectionClass($obj))->isUninitializedLazyObject($obj)); + var_dump(!$reflector->isUninitializedLazyObject($obj)); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/008.phpt b/Zend/tests/lazy_objects/init_trigger_var_export.phpt similarity index 68% rename from Zend/tests/lazy_objects/008.phpt rename to Zend/tests/lazy_objects/init_trigger_var_export.phpt index 56b1b30219b14..315235d5fb379 100644 --- a/Zend/tests/lazy_objects/008.phpt +++ b/Zend/tests/lazy_objects/init_trigger_var_export.phpt @@ -11,10 +11,11 @@ class C { } } +$reflector = new ReflectionClass(C::class); + print "# Ghost:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); @@ -24,8 +25,7 @@ print "\n"; print "# Virtual:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/initialize_001.phpt b/Zend/tests/lazy_objects/initializeLazyObject.phpt similarity index 72% rename from Zend/tests/lazy_objects/initialize_001.phpt rename to Zend/tests/lazy_objects/initializeLazyObject.phpt index 5f1966974af3e..d1770c2c083a3 100644 --- a/Zend/tests/lazy_objects/initialize_001.phpt +++ b/Zend/tests/lazy_objects/initializeLazyObject.phpt @@ -10,7 +10,7 @@ class C { function test(string $name, object $obj) { printf("# %s:\n", $name); - $reflector = new ReflectionClass($obj); + $reflector = new ReflectionClass(C::class); printf("Initialized:\n"); var_dump(!$reflector->isUninitializedLazyObject($obj)); @@ -21,16 +21,16 @@ function test(string $name, object $obj) { var_dump(!$reflector->isUninitializedLazyObject($obj)); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->a = 1; }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); $c = new C(); $c->a = 1; diff --git a/Zend/tests/lazy_objects/initialize_005.phpt b/Zend/tests/lazy_objects/initializeLazyObject_error.phpt similarity index 72% rename from Zend/tests/lazy_objects/initialize_005.phpt rename to Zend/tests/lazy_objects/initializeLazyObject_error.phpt index a2449aec79125..e81762a4dd748 100644 --- a/Zend/tests/lazy_objects/initialize_005.phpt +++ b/Zend/tests/lazy_objects/initializeLazyObject_error.phpt @@ -10,7 +10,7 @@ class C { function test(string $name, object $obj) { printf("# %s:\n", $name); - $reflector = new ReflectionClass($obj); + $reflector = new ReflectionClass(C::class); var_dump(!$reflector->isUninitializedLazyObject($obj)); try { @@ -22,16 +22,16 @@ function test(string $name, object $obj) { var_dump(!$reflector->isUninitializedLazyObject($obj)); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); throw new \Exception('initializer exception'); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); throw new \Exception('initializer exception'); }); diff --git a/Zend/tests/lazy_objects/initialize_002.phpt b/Zend/tests/lazy_objects/initializeLazyObject_noop_on_initialized_object.phpt similarity index 67% rename from Zend/tests/lazy_objects/initialize_002.phpt rename to Zend/tests/lazy_objects/initializeLazyObject_noop_on_initialized_object.phpt index 867b2d54b53d9..266e92cbc4b19 100644 --- a/Zend/tests/lazy_objects/initialize_002.phpt +++ b/Zend/tests/lazy_objects/initializeLazyObject_noop_on_initialized_object.phpt @@ -10,7 +10,7 @@ class C { function test(string $name, object $obj) { printf("# %s:\n", $name); - $reflector = new ReflectionClass($obj); + $reflector = new ReflectionClass(C::class); var_dump($obj->a); @@ -21,16 +21,16 @@ function test(string $name, object $obj) { var_dump(!$reflector->isUninitializedLazyObject($obj)); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->a = 1; }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); $c = new C(); $c->a = 1; @@ -39,12 +39,12 @@ $obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); test('Virtual', $obj); ---EXPECT-- +--EXPECTF-- # Ghost: string(11) "initializer" int(1) bool(true) -object(C)#2 (1) { +object(C)#%d (1) { ["a"]=> int(1) } @@ -53,7 +53,7 @@ bool(true) string(11) "initializer" int(1) bool(true) -object(C)#4 (1) { +object(C)#%d (1) { ["a"]=> int(1) } diff --git a/Zend/tests/lazy_objects/005.phpt b/Zend/tests/lazy_objects/initializer_must_return_the_right_type.phpt similarity index 90% rename from Zend/tests/lazy_objects/005.phpt rename to Zend/tests/lazy_objects/initializer_must_return_the_right_type.phpt index 050b55871e2d1..54f5b79decf6e 100644 --- a/Zend/tests/lazy_objects/005.phpt +++ b/Zend/tests/lazy_objects/initializer_must_return_the_right_type.phpt @@ -24,9 +24,11 @@ class E extends B { } } +$reflector = new ReflectionClass(C::class); + print "# Ghost initializer must return NULL or no value:\n"; -$obj = (new ReflectionClass(C::class))->newLazyGhost(function ($obj) { +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); return new stdClass; @@ -50,8 +52,7 @@ $tests = [ ]; foreach ($tests as [$class, $instance]) { - $reflector = new ReflectionClass($class); - $obj = $reflector->newLazyProxy(function ($obj) use ($instance) { + $obj = (new ReflectionClass($class))->newLazyProxy(function ($obj) use ($instance) { var_dump("initializer"); $instance->b = 1; return $instance; @@ -73,8 +74,7 @@ $tests = [ ]; foreach ($tests as [$class, $instance]) { - $obj = (new ReflectionClass($class))->newInstanceWithoutConstructor(); - (new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) use ($instance) { + $obj = (new ReflectionClass($class))->newLazyProxy(function ($obj) use ($instance) { var_dump("initializer"); return $instance; }); @@ -87,7 +87,7 @@ foreach ($tests as [$class, $instance]) { } } -$obj = (new ReflectionClass(C::class))->newLazyProxy(function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return $obj; }); diff --git a/Zend/tests/lazy_objects/isUninitializedLazyObject.phpt b/Zend/tests/lazy_objects/isUninitializedLazyObject.phpt new file mode 100644 index 0000000000000..82989b78409be --- /dev/null +++ b/Zend/tests/lazy_objects/isUninitializedLazyObject.phpt @@ -0,0 +1,49 @@ +--TEST-- +Lazy objects: ReflectionClass::isUninitializedLazyObject() +--FILE-- +isUninitializedLazyObject($obj)); + var_dump($obj->a); + var_dump($reflector->isUninitializedLazyObject($obj)); +} + +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->a = 1; +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function ($obj) { + var_dump("initializer"); + $obj = new C(); + $obj->a = 1; + return $obj; +}); + +test('Proxy', $obj); + +?> +--EXPECT-- +# Ghost +bool(true) +string(11) "initializer" +int(1) +bool(false) +# Proxy +bool(true) +string(11) "initializer" +int(1) +bool(false) diff --git a/Zend/tests/lazy_objects/is_initialized_001.phpt b/Zend/tests/lazy_objects/is_initialized_001.phpt deleted file mode 100644 index d121417a889db..0000000000000 --- a/Zend/tests/lazy_objects/is_initialized_001.phpt +++ /dev/null @@ -1,26 +0,0 @@ ---TEST-- -Lazy objects: ReflectionClass::isInitialized ---FILE-- -newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { - var_dump("initializer"); - $obj->a = 1; -}); - -$reflector = new ReflectionClass($obj); -var_dump(!$reflector->isUninitializedLazyObject($obj)); - -var_dump($obj->a); - -var_dump(!$reflector->isUninitializedLazyObject($obj)); ---EXPECTF-- -bool(false) -string(11) "initializer" -int(1) -bool(true) diff --git a/Zend/tests/lazy_objects/is_uninitialized_lazy_object.phpt b/Zend/tests/lazy_objects/is_uninitialized_lazy_object.phpt deleted file mode 100644 index 62fd7c1c70542..0000000000000 --- a/Zend/tests/lazy_objects/is_uninitialized_lazy_object.phpt +++ /dev/null @@ -1,31 +0,0 @@ ---TEST-- -Lazy objects: isUninitializedLazyObject() ---FILE-- -a = 1; - } -} - -$reflector = new ReflectionClass(C::class); - -$obj = $reflector->newLazyGhost(function () {}); -var_dump($reflector->isUninitializedLazyObject($obj)); -$reflector->initializeLazyObject($obj); -var_dump($reflector->isUninitializedLazyObject($obj)); - -$obj = $reflector->newLazyProxy(function () { return new C(); }); -var_dump($reflector->isUninitializedLazyObject($obj)); -$reflector->initializeLazyObject($obj); -var_dump($reflector->isUninitializedLazyObject($obj)); - -?> ---EXPECT-- -bool(true) -bool(false) -bool(true) -bool(false) diff --git a/Zend/tests/lazy_objects/isset_002.phpt b/Zend/tests/lazy_objects/isset_hooked_may_initialize.phpt similarity index 75% rename from Zend/tests/lazy_objects/isset_002.phpt rename to Zend/tests/lazy_objects/isset_hooked_may_initialize.phpt index 39722791e5687..ef4deb1a952f9 100644 --- a/Zend/tests/lazy_objects/isset_002.phpt +++ b/Zend/tests/lazy_objects/isset_hooked_may_initialize.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: hooked property isset may initialize object +Lazy objects: hooked property isset initializes object if hook observes object state --FILE-- newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(1); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(1); }); diff --git a/Zend/tests/lazy_objects/isset_003.phpt b/Zend/tests/lazy_objects/isset_hooked_may_not_initialize.phpt similarity index 71% rename from Zend/tests/lazy_objects/isset_003.phpt rename to Zend/tests/lazy_objects/isset_hooked_may_not_initialize.phpt index 9ade21d693e1e..18d420064f72d 100644 --- a/Zend/tests/lazy_objects/isset_003.phpt +++ b/Zend/tests/lazy_objects/isset_hooked_may_not_initialize.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: hooked property isset may not initialize object +Lazy objects: hooked property isset may does not initialize object if hook does not observe object state --FILE-- newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(1); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(1); }); diff --git a/Zend/tests/lazy_objects/isset_001.phpt b/Zend/tests/lazy_objects/isset_initializes.phpt similarity index 78% rename from Zend/tests/lazy_objects/isset_001.phpt rename to Zend/tests/lazy_objects/isset_initializes.phpt index 3f9c918c9ebfc..d70ae76ccc84e 100644 --- a/Zend/tests/lazy_objects/isset_001.phpt +++ b/Zend/tests/lazy_objects/isset_initializes.phpt @@ -22,16 +22,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(1); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(1); }); diff --git a/Zend/tests/lazy_objects/mark_as_initialized_001.phpt b/Zend/tests/lazy_objects/markLazyObjectAsInitialized.phpt similarity index 76% rename from Zend/tests/lazy_objects/mark_as_initialized_001.phpt rename to Zend/tests/lazy_objects/markLazyObjectAsInitialized.phpt index b31852b49ff35..72f6476bc9afa 100644 --- a/Zend/tests/lazy_objects/mark_as_initialized_001.phpt +++ b/Zend/tests/lazy_objects/markLazyObjectAsInitialized.phpt @@ -10,7 +10,7 @@ class C { function test(string $name, object $obj) { printf("# %s:\n", $name); - $reflector = new ReflectionClass($obj); + $reflector = new ReflectionClass(C::class); printf("Initialized:\n"); var_dump(!$reflector->isUninitializedLazyObject($obj)); @@ -23,16 +23,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->a = 1; }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); $c = new C(); $c->a = 1; diff --git a/Zend/tests/lazy_objects/new_instance_lazy_001.phpt b/Zend/tests/lazy_objects/new_instance_lazy_001.phpt deleted file mode 100644 index 32c2e1680c65c..0000000000000 --- a/Zend/tests/lazy_objects/new_instance_lazy_001.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Lazy objects: newInstanceLazy can not instantiate internal classes ---FILE-- -newInstanceWithoutConstructor(); - -foreach (['resetAsLazyGhost', 'resetAsLazyProxy'] as $strategy) { - try { - $reflector->$strategy($obj, function ($obj) { - var_dump("initializer"); - }); - } catch (Error $e) { - printf("%s: %s\n", $e::class, $e->getMessage()); - } -} ---EXPECT-- -Error: Cannot make instance of internal class lazy: ReflectionClass is internal -Error: Cannot make instance of internal class lazy: ReflectionClass is internal diff --git a/Zend/tests/lazy_objects/new_instance_lazy_002.phpt b/Zend/tests/lazy_objects/new_instance_lazy_002.phpt deleted file mode 100644 index c8f3463c94edc..0000000000000 --- a/Zend/tests/lazy_objects/new_instance_lazy_002.phpt +++ /dev/null @@ -1,21 +0,0 @@ ---TEST-- -Lazy objects: newInstanceLazy can not instantiate sub-class of internal classes ---FILE-- -newInstanceWithoutConstructor(); - try { - $reflector->$strategy($obj, function ($obj) { - var_dump("initializer"); - }); - } catch (Error $e) { - printf("%s: %s\n", $e::class, $e->getMessage()); - } -} ---EXPECT-- -Error: Cannot make instance of internal class lazy: C inherits internal class ReflectionClass -Error: Cannot make instance of internal class lazy: C inherits internal class ReflectionClass diff --git a/Zend/tests/lazy_objects/new_instance_lazy_003.phpt b/Zend/tests/lazy_objects/new_instance_lazy_003.phpt deleted file mode 100644 index 00516a19b737f..0000000000000 --- a/Zend/tests/lazy_objects/new_instance_lazy_003.phpt +++ /dev/null @@ -1,22 +0,0 @@ ---TEST-- -Lazy objects: newInstanceLazy can instantiate sub-class of user classes ---FILE-- -newInstanceWithoutConstructor(); - $reflector->$strategy($obj, function ($obj) { - var_dump("initializer"); - }); - var_dump($obj); -} - ---EXPECTF-- -object(C)#%d (0) { -} -object(C)#%d (0) { -} diff --git a/Zend/tests/lazy_objects/new_instance_lazy_004.phpt b/Zend/tests/lazy_objects/new_instance_lazy_004.phpt deleted file mode 100644 index c4782b46b943d..0000000000000 --- a/Zend/tests/lazy_objects/new_instance_lazy_004.phpt +++ /dev/null @@ -1,18 +0,0 @@ ---TEST-- -Lazy objects: newInstanceLazy can instantiate stdClass ---FILE-- -newInstanceWithoutConstructor(); - $reflector->$strategy($obj, function ($obj) { - var_dump("initializer"); - }); - var_dump($obj); -} ---EXPECTF-- -object(stdClass)#%d (0) { -} -object(stdClass)#%d (0) { -} diff --git a/Zend/tests/lazy_objects/new_instance_lazy_005.phpt b/Zend/tests/lazy_objects/new_instance_lazy_005.phpt deleted file mode 100644 index fb028149c021b..0000000000000 --- a/Zend/tests/lazy_objects/new_instance_lazy_005.phpt +++ /dev/null @@ -1,21 +0,0 @@ ---TEST-- -Lazy objects: newInstanceLazy can instantiate sub-class of stdClass ---FILE-- -newInstanceWithoutConstructor(); - $reflector->$strategy($obj, function ($obj) { - var_dump("initializer"); - }); - var_dump($obj); -} - ---EXPECTF-- -object(C)#%d (0) { -} -object(C)#%d (0) { -} diff --git a/Zend/tests/lazy_objects/realize_001.phpt b/Zend/tests/lazy_objects/realize.phpt similarity index 86% rename from Zend/tests/lazy_objects/realize_001.phpt rename to Zend/tests/lazy_objects/realize.phpt index 69d78cdbe1f8f..f57303cb4b00a 100644 --- a/Zend/tests/lazy_objects/realize_001.phpt +++ b/Zend/tests/lazy_objects/realize.phpt @@ -23,9 +23,10 @@ class C extends B { } function test(string $name, object $obj) { + $reflector = new ReflectionClass(C::class); + printf("# %s:\n", $name); - $reflector = new ReflectionClass($obj); var_dump(!$reflector->isUninitializedLazyObject($obj)); $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, 'a1'); @@ -52,16 +53,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/realize_003.phpt b/Zend/tests/lazy_objects/realize_no_props.phpt similarity index 100% rename from Zend/tests/lazy_objects/realize_003.phpt rename to Zend/tests/lazy_objects/realize_no_props.phpt diff --git a/Zend/tests/lazy_objects/props_of_proxy_must_not_be_lazy_004.phpt b/Zend/tests/lazy_objects/realize_proxy_overridden.phpt similarity index 85% rename from Zend/tests/lazy_objects/props_of_proxy_must_not_be_lazy_004.phpt rename to Zend/tests/lazy_objects/realize_proxy_overridden.phpt index 3858f3ff4216c..9da07059b1e10 100644 --- a/Zend/tests/lazy_objects/props_of_proxy_must_not_be_lazy_004.phpt +++ b/Zend/tests/lazy_objects/realize_proxy_overridden.phpt @@ -22,9 +22,10 @@ class C extends B { } function test(string $name, object $obj) { + $reflector = new ReflectionClass(C::class); + printf("# %s:\n", $name); - $reflector = new ReflectionClass($obj); var_dump(!$reflector->isUninitializedLazyObject($obj)); $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, 'a1'); @@ -47,16 +48,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/realize_002.phpt b/Zend/tests/lazy_objects/realize_skipped.phpt similarity index 86% rename from Zend/tests/lazy_objects/realize_002.phpt rename to Zend/tests/lazy_objects/realize_skipped.phpt index 6451b5e0127de..4d1c94a311cfe 100644 --- a/Zend/tests/lazy_objects/realize_002.phpt +++ b/Zend/tests/lazy_objects/realize_skipped.phpt @@ -23,9 +23,10 @@ class C extends B { } function test(string $name, object $obj) { + $reflector = new ReflectionClass(C::class); + printf("# %s:\n", $name); - $reflector = new ReflectionClass($obj); var_dump(!$reflector->isUninitializedLazyObject($obj)); $reflector->getProperty('a')->skipLazyInitialization($obj); @@ -55,16 +56,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/make_lazy_already_exception.phpt b/Zend/tests/lazy_objects/reset_as_lazy_already_exception.phpt similarity index 56% rename from Zend/tests/lazy_objects/make_lazy_already_exception.phpt rename to Zend/tests/lazy_objects/reset_as_lazy_already_exception.phpt index 5dc8fb675d550..7f1f25486d2b4 100644 --- a/Zend/tests/lazy_objects/make_lazy_already_exception.phpt +++ b/Zend/tests/lazy_objects/reset_as_lazy_already_exception.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: makeLazy() on already lazy object is not allowed +Lazy objects: resetAsLazy*() on already lazy object is not allowed --FILE-- resetAsLazyGhost($obj, function () {}); +$reflector->resetAsLazyGhost($obj, function () {}); try { - $r->resetAsLazyGhost($obj, function ($obj) { + $reflector->resetAsLazyGhost($obj, function ($obj) { }); } catch (\Exception $e) { printf("%s: %s\n", $e::class, $e->getMessage()); @@ -23,23 +24,23 @@ try { printf("# Virtual:\n"); $obj = new C(); -$r->resetAsLazyProxy($obj, function () {}); +$reflector->resetAsLazyProxy($obj, function () {}); try { - $r->resetAsLazyProxy($obj, function ($obj) { + $reflector->resetAsLazyProxy($obj, function ($obj) { }); } catch (\Exception $e) { printf("%s: %s\n", $e::class, $e->getMessage()); } $obj = new C(); -$r->resetAsLazyProxy($obj, function () { +$reflector->resetAsLazyProxy($obj, function () { return new C(); }); -$r->initializeLazyObject($obj); +$reflector->initializeLazyObject($obj); try { - $r->resetAsLazyProxy($obj, function ($obj) { + $reflector->resetAsLazyProxy($obj, function ($obj) { }); } catch (\Exception $e) { printf("%s: %s\n", $e::class, $e->getMessage()); diff --git a/Zend/tests/lazy_objects/make_lazy_destructor_001.phpt b/Zend/tests/lazy_objects/reset_as_lazy_calls_destructor.phpt similarity index 78% rename from Zend/tests/lazy_objects/make_lazy_destructor_001.phpt rename to Zend/tests/lazy_objects/reset_as_lazy_calls_destructor.phpt index e5400d7f51126..f7ed0178a6175 100644 --- a/Zend/tests/lazy_objects/make_lazy_destructor_001.phpt +++ b/Zend/tests/lazy_objects/reset_as_lazy_calls_destructor.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: makeLazy calls destructor of pre-existing object +Lazy objects: resetAsLazy*() calls destructor of pre-existing object --FILE-- resetAsLazyGhost($obj, function ($obj) { +$reflector->resetAsLazyGhost($obj, function ($obj) { var_dump("initializer"); $obj->__construct(); }); @@ -32,7 +34,7 @@ print "# Virtual:\n"; $obj = new C(); print "In makeLazy\n"; -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$reflector->resetAsLazyProxy($obj, function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/021.phpt b/Zend/tests/lazy_objects/reset_as_lazy_deletes_reference_source_type.phpt similarity index 85% rename from Zend/tests/lazy_objects/021.phpt rename to Zend/tests/lazy_objects/reset_as_lazy_deletes_reference_source_type.phpt index c4cc63c4a9743..2af1c07f23e3c 100644 --- a/Zend/tests/lazy_objects/021.phpt +++ b/Zend/tests/lazy_objects/reset_as_lazy_deletes_reference_source_type.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: reference source type is deleted by makeLazy() +Lazy objects: resetAsLazy deletes reference source type --FILE-- getMessage()); } -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector->resetAsLazyGhost($obj, function ($obj) { var_dump("initializer"); $obj->__construct(); }); @@ -39,7 +41,7 @@ try { } catch (\Error $e) { printf("%s: %s\n", $e::class, $e->getMessage()); } -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$reflector->resetAsLazyProxy($obj, function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/make_lazy_destructor_003.phpt b/Zend/tests/lazy_objects/reset_as_lazy_destructor_exception.phpt similarity index 81% rename from Zend/tests/lazy_objects/make_lazy_destructor_003.phpt rename to Zend/tests/lazy_objects/reset_as_lazy_destructor_exception.phpt index 4a0653ba327ec..0a6e2977f524c 100644 --- a/Zend/tests/lazy_objects/make_lazy_destructor_003.phpt +++ b/Zend/tests/lazy_objects/reset_as_lazy_destructor_exception.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: Destructor exception in makeLazy +Lazy objects: Destructor exception in resetAsLazy*() --FILE-- resetAsLazyGhost($obj, function ($obj) { + $reflector->resetAsLazyGhost($obj, function ($obj) { var_dump("initializer"); $obj->__construct(); }); @@ -28,7 +30,7 @@ try { } // Object was not made lazy -var_dump(!(new ReflectionClass($obj))->isUninitializedLazyObject($obj)); +var_dump(!$reflector->isUninitializedLazyObject($obj)); print "# Virtual:\n"; diff --git a/Zend/tests/lazy_objects/feedback_008.phpt b/Zend/tests/lazy_objects/reset_as_lazy_initialized_proxy.phpt similarity index 93% rename from Zend/tests/lazy_objects/feedback_008.phpt rename to Zend/tests/lazy_objects/reset_as_lazy_initialized_proxy.phpt index d309a2cd67d91..d277a4e247d6c 100644 --- a/Zend/tests/lazy_objects/feedback_008.phpt +++ b/Zend/tests/lazy_objects/reset_as_lazy_initialized_proxy.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: feedback 008 +Lazy objects: resetAsLazy*() can reset initialized proxy --FILE-- resetAsLazyGhost($obj, function ($obj) { +$reflector->resetAsLazyGhost($obj, function ($obj) { var_dump("initializer"); $obj->__construct(); }, ReflectionClass::SKIP_DESTRUCTOR); @@ -32,7 +34,7 @@ print "# Virtual:\n"; $obj = new C(); print "In makeLazy\n"; -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$reflector->resetAsLazyProxy($obj, function ($obj) { var_dump("initializer"); return new C(); }, ReflectionClass::SKIP_DESTRUCTOR); diff --git a/Zend/tests/lazy_objects/reset_readonly_001.phpt b/Zend/tests/lazy_objects/reset_as_lazy_readonly.phpt similarity index 95% rename from Zend/tests/lazy_objects/reset_readonly_001.phpt rename to Zend/tests/lazy_objects/reset_as_lazy_readonly.phpt index f673d00bb7665..128e825e539a7 100644 --- a/Zend/tests/lazy_objects/reset_readonly_001.phpt +++ b/Zend/tests/lazy_objects/reset_as_lazy_readonly.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: resetAsLazy preserves readonly semantics +Lazy objects: resetAsLazy*() preserves readonly semantics --FILE-- resetAsLazyGhost($obj, function ($obj) { +$reflector->resetAsLazyGhost($obj, function ($obj) { var_dump("initializer"); $obj->__construct(); }); @@ -32,7 +34,7 @@ var_dump($obj); print "# Virtual:\n"; $obj = new C(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$reflector->resetAsLazyProxy($obj, function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/rfc_example_001.phpt b/Zend/tests/lazy_objects/rfc/rfc_example_001.phpt similarity index 100% rename from Zend/tests/lazy_objects/rfc_example_001.phpt rename to Zend/tests/lazy_objects/rfc/rfc_example_001.phpt diff --git a/Zend/tests/lazy_objects/rfc_example_002.phpt b/Zend/tests/lazy_objects/rfc/rfc_example_002.phpt similarity index 100% rename from Zend/tests/lazy_objects/rfc_example_002.phpt rename to Zend/tests/lazy_objects/rfc/rfc_example_002.phpt diff --git a/Zend/tests/lazy_objects/rfc_example_003.phpt b/Zend/tests/lazy_objects/rfc/rfc_example_003.phpt similarity index 100% rename from Zend/tests/lazy_objects/rfc_example_003.phpt rename to Zend/tests/lazy_objects/rfc/rfc_example_003.phpt diff --git a/Zend/tests/lazy_objects/rfc_example_004.phpt b/Zend/tests/lazy_objects/rfc/rfc_example_004.phpt similarity index 100% rename from Zend/tests/lazy_objects/rfc_example_004.phpt rename to Zend/tests/lazy_objects/rfc/rfc_example_004.phpt diff --git a/Zend/tests/lazy_objects/rfc_example_005.phpt b/Zend/tests/lazy_objects/rfc/rfc_example_005.phpt similarity index 100% rename from Zend/tests/lazy_objects/rfc_example_005.phpt rename to Zend/tests/lazy_objects/rfc/rfc_example_005.phpt diff --git a/Zend/tests/lazy_objects/rfc_example_006.phpt b/Zend/tests/lazy_objects/rfc/rfc_example_006.phpt similarity index 100% rename from Zend/tests/lazy_objects/rfc_example_006.phpt rename to Zend/tests/lazy_objects/rfc/rfc_example_006.phpt diff --git a/Zend/tests/lazy_objects/rfc_example_007.phpt b/Zend/tests/lazy_objects/rfc/rfc_example_007.phpt similarity index 100% rename from Zend/tests/lazy_objects/rfc_example_007.phpt rename to Zend/tests/lazy_objects/rfc/rfc_example_007.phpt diff --git a/Zend/tests/lazy_objects/rfc_example_008.phpt b/Zend/tests/lazy_objects/rfc/rfc_example_008.phpt similarity index 100% rename from Zend/tests/lazy_objects/rfc_example_008.phpt rename to Zend/tests/lazy_objects/rfc/rfc_example_008.phpt diff --git a/Zend/tests/lazy_objects/rfc_example_009.phpt b/Zend/tests/lazy_objects/rfc/rfc_example_009.phpt similarity index 100% rename from Zend/tests/lazy_objects/rfc_example_009.phpt rename to Zend/tests/lazy_objects/rfc/rfc_example_009.phpt diff --git a/Zend/tests/lazy_objects/rfc_example_010.phpt b/Zend/tests/lazy_objects/rfc/rfc_example_010.phpt similarity index 100% rename from Zend/tests/lazy_objects/rfc_example_010.phpt rename to Zend/tests/lazy_objects/rfc/rfc_example_010.phpt diff --git a/Zend/tests/lazy_objects/rfc_example_011.phpt b/Zend/tests/lazy_objects/rfc/rfc_example_011.phpt similarity index 100% rename from Zend/tests/lazy_objects/rfc_example_011.phpt rename to Zend/tests/lazy_objects/rfc/rfc_example_011.phpt diff --git a/Zend/tests/lazy_objects/rfc_example_012.phpt b/Zend/tests/lazy_objects/rfc/rfc_example_012.phpt similarity index 100% rename from Zend/tests/lazy_objects/rfc_example_012.phpt rename to Zend/tests/lazy_objects/rfc/rfc_example_012.phpt diff --git a/Zend/tests/lazy_objects/serialize_006.phpt b/Zend/tests/lazy_objects/serialize___serialize_may_initialize.phpt similarity index 69% rename from Zend/tests/lazy_objects/serialize_006.phpt rename to Zend/tests/lazy_objects/serialize___serialize_may_initialize.phpt index 4c965c0fe934e..6d53449e1ec92 100644 --- a/Zend/tests/lazy_objects/serialize_006.phpt +++ b/Zend/tests/lazy_objects/serialize___serialize_may_initialize.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: __serialize may initialize object +Lazy objects: serialize() initializes object if __serialize observes object state --FILE-- newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->a = 1; }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); $c = new c(); $c->a = 1; diff --git a/Zend/tests/lazy_objects/serialize_005.phpt b/Zend/tests/lazy_objects/serialize___serialize_may_not_initialize.phpt similarity index 62% rename from Zend/tests/lazy_objects/serialize_005.phpt rename to Zend/tests/lazy_objects/serialize___serialize_may_not_initialize.phpt index e9817b6a3a771..e3b5ceadb4e8f 100644 --- a/Zend/tests/lazy_objects/serialize_005.phpt +++ b/Zend/tests/lazy_objects/serialize___serialize_may_not_initialize.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: serialize does not force initialization of object if the __serialize method is used +Lazy objects: serialize() does not initialize object if __serialize does observe object state --FILE-- newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/serialize_007.phpt b/Zend/tests/lazy_objects/serialize___sleep_initializes.phpt similarity index 74% rename from Zend/tests/lazy_objects/serialize_007.phpt rename to Zend/tests/lazy_objects/serialize___sleep_initializes.phpt index d817aaf5279be..4e183b3b1b148 100644 --- a/Zend/tests/lazy_objects/serialize_007.phpt +++ b/Zend/tests/lazy_objects/serialize___sleep_initializes.phpt @@ -18,16 +18,16 @@ function test(string $name, object $obj) { var_dump($serialized, $unserialized); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->a = 1; }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); $c = new C(); $c->a = 1; diff --git a/Zend/tests/lazy_objects/serialize_008.phpt b/Zend/tests/lazy_objects/serialize___sleep_skip_flag.phpt similarity index 74% rename from Zend/tests/lazy_objects/serialize_008.phpt rename to Zend/tests/lazy_objects/serialize___sleep_skip_flag.phpt index 4ef54498e5b5b..1b7abd55fe4e1 100644 --- a/Zend/tests/lazy_objects/serialize_008.phpt +++ b/Zend/tests/lazy_objects/serialize___sleep_skip_flag.phpt @@ -18,16 +18,16 @@ function test(string $name, object $obj) { var_dump($serialized, $unserialized); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->a = 1; }, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); $obj->a = 1; }, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); diff --git a/Zend/tests/lazy_objects/serialize_009.phpt b/Zend/tests/lazy_objects/serialize___sleep_skip_flag_may_initialize.phpt similarity index 72% rename from Zend/tests/lazy_objects/serialize_009.phpt rename to Zend/tests/lazy_objects/serialize___sleep_skip_flag_may_initialize.phpt index af1876afbddf3..51568f2fe0127 100644 --- a/Zend/tests/lazy_objects/serialize_009.phpt +++ b/Zend/tests/lazy_objects/serialize___sleep_skip_flag_may_initialize.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: __sleep may initialize object +Lazy objects: __sleep initializes object if it observes object state, even with SKIP_INITIALIZATION_ON_SERIALIZE --FILE-- newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->a = 1; }, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); $c = new C(); $c->a = 1; diff --git a/Zend/tests/lazy_objects/serialize_010.phpt b/Zend/tests/lazy_objects/serialize_hook.phpt similarity index 73% rename from Zend/tests/lazy_objects/serialize_010.phpt rename to Zend/tests/lazy_objects/serialize_hook.phpt index 6cc46513a0f6b..dd84899efe316 100644 --- a/Zend/tests/lazy_objects/serialize_010.phpt +++ b/Zend/tests/lazy_objects/serialize_hook.phpt @@ -20,16 +20,16 @@ function test(string $name, object $obj) { var_dump($obj->a); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/serialize_001.phpt b/Zend/tests/lazy_objects/serialize_initializes.phpt similarity index 70% rename from Zend/tests/lazy_objects/serialize_001.phpt rename to Zend/tests/lazy_objects/serialize_initializes.phpt index 2203f83760bcc..eea1361c34800 100644 --- a/Zend/tests/lazy_objects/serialize_001.phpt +++ b/Zend/tests/lazy_objects/serialize_initializes.phpt @@ -17,16 +17,16 @@ function test(string $name, object $obj) { var_dump(serialize($obj)); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/serialize_002.phpt b/Zend/tests/lazy_objects/serialize_props_ht.phpt similarity index 72% rename from Zend/tests/lazy_objects/serialize_002.phpt rename to Zend/tests/lazy_objects/serialize_props_ht.phpt index 9b664f92dbf8f..ebbdb407e20e7 100644 --- a/Zend/tests/lazy_objects/serialize_002.phpt +++ b/Zend/tests/lazy_objects/serialize_props_ht.phpt @@ -20,16 +20,16 @@ function test(string $name, object $obj) { var_dump(serialize($obj)); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/serialize_003.phpt b/Zend/tests/lazy_objects/serialize_skip_flag.phpt similarity index 75% rename from Zend/tests/lazy_objects/serialize_003.phpt rename to Zend/tests/lazy_objects/serialize_skip_flag.phpt index 71da496fb5aba..5ec4989d864b2 100644 --- a/Zend/tests/lazy_objects/serialize_003.phpt +++ b/Zend/tests/lazy_objects/serialize_skip_flag.phpt @@ -19,15 +19,15 @@ function test(string $name, object $obj) { var_dump($serialized, $unserialized); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); }, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); }, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); diff --git a/Zend/tests/lazy_objects/serialize_004.phpt b/Zend/tests/lazy_objects/serialize_skip_flag_props_ht.phpt similarity index 77% rename from Zend/tests/lazy_objects/serialize_004.phpt rename to Zend/tests/lazy_objects/serialize_skip_flag_props_ht.phpt index 70d3fe7dfc8b5..6292317cd3547 100644 --- a/Zend/tests/lazy_objects/serialize_004.phpt +++ b/Zend/tests/lazy_objects/serialize_skip_flag_props_ht.phpt @@ -22,15 +22,15 @@ function test(string $name, object $obj) { var_dump($serialized, $unserialized); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); }, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); }, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); diff --git a/Zend/tests/lazy_objects/set_raw_value_001.phpt b/Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization.phpt similarity index 100% rename from Zend/tests/lazy_objects/set_raw_value_001.phpt rename to Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization.phpt diff --git a/Zend/tests/lazy_objects/skip_initialization_009.phpt b/Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_exception.phpt similarity index 100% rename from Zend/tests/lazy_objects/skip_initialization_009.phpt rename to Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_exception.phpt diff --git a/Zend/tests/lazy_objects/set_raw_value_007.phpt b/Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_initialized.phpt similarity index 100% rename from Zend/tests/lazy_objects/set_raw_value_007.phpt rename to Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_initialized.phpt diff --git a/Zend/tests/lazy_objects/set_raw_value_008.phpt b/Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_no_dynamic_prop.phpt similarity index 100% rename from Zend/tests/lazy_objects/set_raw_value_008.phpt rename to Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_no_dynamic_prop.phpt diff --git a/Zend/tests/lazy_objects/set_raw_value_009.phpt b/Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_readonly.phpt similarity index 100% rename from Zend/tests/lazy_objects/set_raw_value_009.phpt rename to Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_readonly.phpt diff --git a/Zend/tests/lazy_objects/skip_initialization_008.phpt b/Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_readonly_variant.phpt similarity index 100% rename from Zend/tests/lazy_objects/skip_initialization_008.phpt rename to Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_readonly_variant.phpt diff --git a/Zend/tests/lazy_objects/set_raw_value_003.phpt b/Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_realize.phpt similarity index 100% rename from Zend/tests/lazy_objects/set_raw_value_003.phpt rename to Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_realize.phpt diff --git a/Zend/tests/lazy_objects/set_raw_value_006.phpt b/Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_side_effect_destruct.phpt similarity index 100% rename from Zend/tests/lazy_objects/set_raw_value_006.phpt rename to Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_side_effect_destruct.phpt diff --git a/Zend/tests/lazy_objects/set_raw_value_005.phpt b/Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_side_effect_toString.phpt similarity index 100% rename from Zend/tests/lazy_objects/set_raw_value_005.phpt rename to Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_side_effect_toString.phpt diff --git a/Zend/tests/lazy_objects/set_raw_value_004.phpt b/Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_skips___set.phpt similarity index 100% rename from Zend/tests/lazy_objects/set_raw_value_004.phpt rename to Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_skips___set.phpt diff --git a/Zend/tests/lazy_objects/set_raw_value_002.phpt b/Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_skips_hook.phpt similarity index 100% rename from Zend/tests/lazy_objects/set_raw_value_002.phpt rename to Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_skips_hook.phpt diff --git a/Zend/tests/lazy_objects/reflection_lazy_object_skip_property_001.phpt b/Zend/tests/lazy_objects/skipLazyInitialization.phpt similarity index 98% rename from Zend/tests/lazy_objects/reflection_lazy_object_skip_property_001.phpt rename to Zend/tests/lazy_objects/skipLazyInitialization.phpt index ea4cfda907646..4f64dfb1eaa50 100644 --- a/Zend/tests/lazy_objects/reflection_lazy_object_skip_property_001.phpt +++ b/Zend/tests/lazy_objects/skipLazyInitialization.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: ReflectionClass::skipInitializerForProperty() prevent properties from triggering initializer +Lazy objects: ReflectionProperty::skipLazyInitialization() prevent properties from triggering initializer --FILE-- newInstanceWithoutConstructor(); try { - (new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + $obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); @@ -17,9 +18,8 @@ try { print "# Virtual:\n"; -$obj = (new ReflectionClass(DateTime::class))->newInstanceWithoutConstructor(); try { - (new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + $obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); $obj->__construct(); }); diff --git a/Zend/tests/lazy_objects/015.phpt b/Zend/tests/lazy_objects/support_no_internal_sub_classes.phpt similarity index 70% rename from Zend/tests/lazy_objects/015.phpt rename to Zend/tests/lazy_objects/support_no_internal_sub_classes.phpt index 727beb63ecb86..9629f63b20dc8 100644 --- a/Zend/tests/lazy_objects/015.phpt +++ b/Zend/tests/lazy_objects/support_no_internal_sub_classes.phpt @@ -6,11 +6,12 @@ Lazy objects: sub-classes of internal classes can not be initialized lazily class C extends DateTime { } +$reflector = new ReflectionClass(C::class); + print "# Ghost:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); try { - (new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + $obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); @@ -20,9 +21,8 @@ try { print "# Virtual:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); try { - (new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + $obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); $obj->__construct(); }); diff --git a/Zend/tests/lazy_objects/004.phpt b/Zend/tests/lazy_objects/support_readonly_class.phpt similarity index 74% rename from Zend/tests/lazy_objects/004.phpt rename to Zend/tests/lazy_objects/support_readonly_class.phpt index bc71f687f05d7..bb47b0b8af922 100644 --- a/Zend/tests/lazy_objects/004.phpt +++ b/Zend/tests/lazy_objects/support_readonly_class.phpt @@ -11,10 +11,11 @@ readonly class C { } } +$reflector = new ReflectionClass(C::class); + print "# Ghost:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); @@ -25,8 +26,7 @@ var_dump($obj); print "# Virtual:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/003.phpt b/Zend/tests/lazy_objects/support_readonly_prop.phpt similarity index 74% rename from Zend/tests/lazy_objects/003.phpt rename to Zend/tests/lazy_objects/support_readonly_prop.phpt index 589f5535a7324..05d674392da5a 100644 --- a/Zend/tests/lazy_objects/003.phpt +++ b/Zend/tests/lazy_objects/support_readonly_prop.phpt @@ -11,10 +11,11 @@ class C { } } +$reflector = new ReflectionClass(C::class); + print "# Ghost:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); @@ -25,8 +26,7 @@ var_dump($obj); print "# Virtual:\n"; -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/support_stdClass.phpt b/Zend/tests/lazy_objects/support_stdClass.phpt new file mode 100644 index 0000000000000..2bc61929cdc81 --- /dev/null +++ b/Zend/tests/lazy_objects/support_stdClass.phpt @@ -0,0 +1,30 @@ +--TEST-- +Lazy objects: stdClass can be initialized lazily +--FILE-- +newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); +var_dump($obj); + +print "# Virtual:\n"; + +$obj = $reflector->newLazyProxy(function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); +var_dump($obj); + +--EXPECTF-- +# Ghost: +object(stdClass)#%d (0) { +} +# Virtual: +object(stdClass)#%d (0) { +} diff --git a/Zend/tests/lazy_objects/support_stdClass_sub_classes.phpt b/Zend/tests/lazy_objects/support_stdClass_sub_classes.phpt new file mode 100644 index 0000000000000..1730dc2fb28ac --- /dev/null +++ b/Zend/tests/lazy_objects/support_stdClass_sub_classes.phpt @@ -0,0 +1,33 @@ +--TEST-- +Lazy objects: sub-classes of stdClass can be initialized lazily +--FILE-- +newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); +var_dump($obj); + +print "# Virtual:\n"; + +$obj = $reflector->newLazyProxy(function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); +var_dump($obj); + +--EXPECTF-- +# Ghost: +object(C)#%d (0) { +} +# Virtual: +object(C)#%d (0) { +} diff --git a/Zend/tests/lazy_objects/unclean_shutdown.phpt b/Zend/tests/lazy_objects/unclean_shutdown.phpt index a5effe34642f9..d162ae2973678 100644 --- a/Zend/tests/lazy_objects/unclean_shutdown.phpt +++ b/Zend/tests/lazy_objects/unclean_shutdown.phpt @@ -7,8 +7,9 @@ class C { public $a; } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { trigger_error('Fatal', E_USER_ERROR); }); diff --git a/Zend/tests/lazy_objects/unset_008.phpt b/Zend/tests/lazy_objects/unset_defined_no_initialize.phpt similarity index 75% rename from Zend/tests/lazy_objects/unset_008.phpt rename to Zend/tests/lazy_objects/unset_defined_no_initialize.phpt index f8d110a963047..164f027c69556 100644 --- a/Zend/tests/lazy_objects/unset_008.phpt +++ b/Zend/tests/lazy_objects/unset_defined_no_initialize.phpt @@ -23,16 +23,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(1); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(1); }); diff --git a/Zend/tests/lazy_objects/unset_010.phpt b/Zend/tests/lazy_objects/unset_hook.phpt similarity index 79% rename from Zend/tests/lazy_objects/unset_010.phpt rename to Zend/tests/lazy_objects/unset_hook.phpt index d22f3dcb83e92..2144af5d7c108 100644 --- a/Zend/tests/lazy_objects/unset_010.phpt +++ b/Zend/tests/lazy_objects/unset_hook.phpt @@ -29,16 +29,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(1); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(1); }); diff --git a/Zend/tests/lazy_objects/unset_005.phpt b/Zend/tests/lazy_objects/unset_magic_circular_may_initialize.phpt similarity index 77% rename from Zend/tests/lazy_objects/unset_005.phpt rename to Zend/tests/lazy_objects/unset_magic_circular_may_initialize.phpt index 11560dfed5032..23b40753694a6 100644 --- a/Zend/tests/lazy_objects/unset_005.phpt +++ b/Zend/tests/lazy_objects/unset_magic_circular_may_initialize.phpt @@ -24,16 +24,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(1); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(1); }); diff --git a/Zend/tests/lazy_objects/unset_004.phpt b/Zend/tests/lazy_objects/unset_magic_may_initialize.phpt similarity index 73% rename from Zend/tests/lazy_objects/unset_004.phpt rename to Zend/tests/lazy_objects/unset_magic_may_initialize.phpt index be63629f532a2..66c2a6f35dba8 100644 --- a/Zend/tests/lazy_objects/unset_004.phpt +++ b/Zend/tests/lazy_objects/unset_magic_may_initialize.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: unset of magic property may initialize object +Lazy objects: unset of magic property initializes object if method observes object state --FILE-- newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(1); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(1); }); diff --git a/Zend/tests/lazy_objects/unset_003.phpt b/Zend/tests/lazy_objects/unset_magic_may_not_initialize.phpt similarity index 69% rename from Zend/tests/lazy_objects/unset_003.phpt rename to Zend/tests/lazy_objects/unset_magic_may_not_initialize.phpt index 2d08d94485d54..df25ae71f462e 100644 --- a/Zend/tests/lazy_objects/unset_003.phpt +++ b/Zend/tests/lazy_objects/unset_magic_may_not_initialize.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: unset of magic property may not initialize object +Lazy objects: unset of magic property may not initialize object if method does not observe object state --FILE-- newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(1); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(1); }); diff --git a/Zend/tests/lazy_objects/unset_009.phpt b/Zend/tests/lazy_objects/unset_skipped_no_initialize.phpt similarity index 78% rename from Zend/tests/lazy_objects/unset_009.phpt rename to Zend/tests/lazy_objects/unset_skipped_no_initialize.phpt index 3de9ca792ce1f..9c61e2406bab7 100644 --- a/Zend/tests/lazy_objects/unset_009.phpt +++ b/Zend/tests/lazy_objects/unset_skipped_no_initialize.phpt @@ -18,7 +18,7 @@ class C { function test(string $name, object $obj) { printf("# %s:\n", $name); - $reflector = new ReflectionClass($obj); + $reflector = new ReflectionClass(C::class); $reflector->getProperty('a')->skipLazyInitialization($obj); $reflector->getProperty('b')->skipLazyInitialization($obj); $reflector->getProperty('c')->skipLazyInitialization($obj); @@ -30,16 +30,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(1); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(1); }); diff --git a/Zend/tests/lazy_objects/unset_006.phpt b/Zend/tests/lazy_objects/unset_undefined_dynamic_initializes.phpt similarity index 76% rename from Zend/tests/lazy_objects/unset_006.phpt rename to Zend/tests/lazy_objects/unset_undefined_dynamic_initializes.phpt index 8f03b11026b55..61362aa6c2e3f 100644 --- a/Zend/tests/lazy_objects/unset_006.phpt +++ b/Zend/tests/lazy_objects/unset_undefined_dynamic_initializes.phpt @@ -21,16 +21,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(1); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(1); }); diff --git a/Zend/tests/lazy_objects/unset_007.phpt b/Zend/tests/lazy_objects/unset_undefined_dynamic_initializes_no_props_ht.phpt similarity index 77% rename from Zend/tests/lazy_objects/unset_007.phpt rename to Zend/tests/lazy_objects/unset_undefined_dynamic_initializes_no_props_ht.phpt index b7ca5adbfdfd4..23944286f221f 100644 --- a/Zend/tests/lazy_objects/unset_007.phpt +++ b/Zend/tests/lazy_objects/unset_undefined_dynamic_initializes_no_props_ht.phpt @@ -22,16 +22,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(1); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(1); }); diff --git a/Zend/tests/lazy_objects/unset_001.phpt b/Zend/tests/lazy_objects/unset_undefined_initializes.phpt similarity index 77% rename from Zend/tests/lazy_objects/unset_001.phpt rename to Zend/tests/lazy_objects/unset_undefined_initializes.phpt index c7f12cafd01d4..d582280b57b30 100644 --- a/Zend/tests/lazy_objects/unset_001.phpt +++ b/Zend/tests/lazy_objects/unset_undefined_initializes.phpt @@ -22,16 +22,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(1); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(1); }); diff --git a/Zend/tests/lazy_objects/use_case_001.phpt b/Zend/tests/lazy_objects/use_case_001.phpt index 0bce225b1effe..c2be34bfebc28 100644 --- a/Zend/tests/lazy_objects/use_case_001.phpt +++ b/Zend/tests/lazy_objects/use_case_001.phpt @@ -23,8 +23,8 @@ class Application { class Container { public function getEntityManagerService(): EntityManager { - $obj = (new ReflectionClass(EntityManager::class))->newInstanceWithoutConstructor(); - (new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { + $reflector = new ReflectionClass(EntityManager::class); + $obj = $reflector->newLazyGhost(function ($obj) { $obj->__construct(); }); return $obj; diff --git a/Zend/tests/lazy_objects/use_case_001b.phpt b/Zend/tests/lazy_objects/use_case_001b.phpt index e32527bca1d78..f2491942d6e87 100644 --- a/Zend/tests/lazy_objects/use_case_001b.phpt +++ b/Zend/tests/lazy_objects/use_case_001b.phpt @@ -23,8 +23,8 @@ class Application { class Container { public function getEntityManagerService(): EntityManager { - $obj = (new ReflectionClass(EntityManager::class))->newInstanceWithoutConstructor(); - (new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { + $reflector = new ReflectionClass(EntityManager::class); + $obj = $reflector->newLazyProxy(function ($obj) { return new EntityManager(); }); return $obj; diff --git a/Zend/tests/lazy_objects/use_case_002.phpt b/Zend/tests/lazy_objects/use_case_002.phpt index 0bbead439c1f7..3a87acdfb8db3 100644 --- a/Zend/tests/lazy_objects/use_case_002.phpt +++ b/Zend/tests/lazy_objects/use_case_002.phpt @@ -23,14 +23,14 @@ class User { class EntityManager { public function lazyLoad(string $fqcn, int $id): object { - $entity = (new ReflectionClass($fqcn))->newInstanceWithoutConstructor(); - (new ReflectionClass($entity))->resetAsLazyGhost($entity, function ($obj) { + $reflector = new ReflectionClass($fqcn); + $entity = $reflector->newLazyGhost(function ($obj) { var_dump('initializer'); - $prop = new ReflectionProperty($obj, 'name'); + $prop = new ReflectionProperty($obj::class, 'name'); $prop->setValue($obj, 'John Doe'); }); - (new ReflectionProperty($entity, 'id'))->setRawValueWithoutLazyInitialization($entity, $id); + (new ReflectionProperty($fqcn, 'id'))->setRawValueWithoutLazyInitialization($entity, $id); return $entity; } diff --git a/Zend/tests/lazy_objects/write_002.phpt b/Zend/tests/lazy_objects/write_dynamic_initializes.phpt similarity index 74% rename from Zend/tests/lazy_objects/write_002.phpt rename to Zend/tests/lazy_objects/write_dynamic_initializes.phpt index 34f76f087d892..b275d24a9aae5 100644 --- a/Zend/tests/lazy_objects/write_002.phpt +++ b/Zend/tests/lazy_objects/write_dynamic_initializes.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: property write to custom property initializes object +Lazy objects: property write to dynamic property initializes object --FILE-- newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/write_005.phpt b/Zend/tests/lazy_objects/write_initializer_exception.phpt similarity index 69% rename from Zend/tests/lazy_objects/write_005.phpt rename to Zend/tests/lazy_objects/write_initializer_exception.phpt index 6aafc032d55fc..2445da55d21d6 100644 --- a/Zend/tests/lazy_objects/write_005.phpt +++ b/Zend/tests/lazy_objects/write_initializer_exception.phpt @@ -19,15 +19,15 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { throw new \Exception('init exception'); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { throw new \Exception('init exception'); }); diff --git a/Zend/tests/lazy_objects/write_001.phpt b/Zend/tests/lazy_objects/write_initializes.phpt similarity index 76% rename from Zend/tests/lazy_objects/write_001.phpt rename to Zend/tests/lazy_objects/write_initializes.phpt index d5c4cb8fe01b6..bc32d8bfff0c9 100644 --- a/Zend/tests/lazy_objects/write_001.phpt +++ b/Zend/tests/lazy_objects/write_initializes.phpt @@ -21,16 +21,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/write_004.phpt b/Zend/tests/lazy_objects/write_magic_circular_may_initialize.phpt similarity index 76% rename from Zend/tests/lazy_objects/write_004.phpt rename to Zend/tests/lazy_objects/write_magic_circular_may_initialize.phpt index 6ea60ad2d04e2..8fdc882bbe5e1 100644 --- a/Zend/tests/lazy_objects/write_004.phpt +++ b/Zend/tests/lazy_objects/write_magic_circular_may_initialize.phpt @@ -24,16 +24,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/write_003.phpt b/Zend/tests/lazy_objects/write_magic_may_initialize.phpt similarity index 76% rename from Zend/tests/lazy_objects/write_003.phpt rename to Zend/tests/lazy_objects/write_magic_may_initialize.phpt index 288b8125820f6..4804a72fce438 100644 --- a/Zend/tests/lazy_objects/write_003.phpt +++ b/Zend/tests/lazy_objects/write_magic_may_initialize.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy objects: property write to magic property initializes object +Lazy objects: property write to magic property initializes object if method updates object state --FILE-- newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); diff --git a/Zend/tests/lazy_objects/write_006.phpt b/Zend/tests/lazy_objects/write_skipped_no_initialize.phpt similarity index 77% rename from Zend/tests/lazy_objects/write_006.phpt rename to Zend/tests/lazy_objects/write_skipped_no_initialize.phpt index 70b1b0c33b712..e2ee38e9ecb5b 100644 --- a/Zend/tests/lazy_objects/write_006.phpt +++ b/Zend/tests/lazy_objects/write_skipped_no_initialize.phpt @@ -16,7 +16,7 @@ class C { function test(string $name, object $obj) { printf("# %s:\n", $name); - $reflector = new ReflectionClass($obj); + $reflector = new ReflectionClass(C::class); $reflector->getProperty('a')->skipLazyInitialization($obj); $reflector->getProperty('b')->skipLazyInitialization($obj); $reflector->getProperty('c')->skipLazyInitialization($obj); @@ -28,16 +28,16 @@ function test(string $name, object $obj) { var_dump($obj); } -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyGhost($obj, function ($obj) { +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { var_dump("initializer"); $obj->__construct(); }); test('Ghost', $obj); -$obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); -(new ReflectionClass($obj))->resetAsLazyProxy($obj, function ($obj) { +$obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); return new C(); }); From 36c70ee433f7659d29f1ff26e15bae91c9633264 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Thu, 25 Jul 2024 22:13:05 +0200 Subject: [PATCH 03/56] Test cleanup --- Zend/tests/lazy_objects/clone_calls___clone_once.phpt | 4 ++-- Zend/tests/lazy_objects/clone_initialized.phpt | 4 ++-- Zend/tests/lazy_objects/clone_initializer_exception.phpt | 4 ++-- Zend/tests/lazy_objects/clone_initializes.phpt | 4 ++-- Zend/tests/lazy_objects/dtor_called_if_init.phpt | 8 ++++---- Zend/tests/lazy_objects/dtor_not_called_if_not_init.phpt | 4 ++-- Zend/tests/lazy_objects/fetch_coalesce_initializes.phpt | 4 ++-- .../fetch_coalesce_non_existing_initializes.phpt | 4 ++-- .../lazy_objects/fetch_declared_prop_initializes.phpt | 4 ++-- .../lazy_objects/fetch_dynamic_prop_initializes.phpt | 4 ++-- .../tests/lazy_objects/fetch_hook_may_not_initialize.phpt | 4 ++-- .../lazy_objects/fetch_hook_virtual_may_initialize.phpt | 4 ++-- .../fetch_hook_virtual_may_not_initialize.phpt | 4 ++-- .../lazy_objects/fetch_magic_prop_may_initialize.phpt | 4 ++-- .../lazy_objects/fetch_magic_prop_may_not_initialize.phpt | 4 ++-- .../fetch_magic_prop_recursive_may_initialize.phpt | 4 ++-- Zend/tests/lazy_objects/fetch_op_dynamic_error.phpt | 4 ++-- .../lazy_objects/fetch_op_dynamic_prop_initializes.phpt | 4 ++-- Zend/tests/lazy_objects/fetch_op_error.phpt | 4 ++-- Zend/tests/lazy_objects/fetch_op_initializes.phpt | 4 ++-- .../fetch_op_skipped_prop_does_not_initialize.phpt | 4 ++-- Zend/tests/lazy_objects/fetch_ref_initializes.phpt | 4 ++-- .../fetch_ref_skipped_prop_does_not_initialize.phpt | 4 ++-- .../fetch_skipped_prop_does_not_initialize.phpt | 4 ++-- .../final_classes_can_be_initialized_lazily.phpt | 4 ++-- Zend/tests/lazy_objects/gc_001.phpt | 8 ++++---- Zend/tests/lazy_objects/gc_002.phpt | 8 ++++---- Zend/tests/lazy_objects/gc_003.phpt | 8 ++++---- Zend/tests/lazy_objects/gc_004.phpt | 8 ++++---- Zend/tests/lazy_objects/gc_005.phpt | 8 ++++---- .../lazy_objects/init_exception_leaves_object_lazy.phpt | 4 ++-- .../init_exception_reverts_initializer_changes.phpt | 6 +++--- ...t_exception_reverts_initializer_changes_dyn_props.phpt | 6 +++--- ...tion_reverts_initializer_changes_dyn_props_and_ht.phpt | 6 +++--- ...ption_reverts_initializer_changes_overridden_prop.phpt | 4 ++-- ...it_exception_reverts_initializer_changes_props_ht.phpt | 6 +++--- ...xception_reverts_initializer_changes_props_ht_ref.phpt | 6 +++--- .../tests/lazy_objects/init_handles_ref_source_types.phpt | 6 +++--- .../init_handles_ref_source_types_exception.phpt | 6 +++--- Zend/tests/lazy_objects/init_trigger_array_cast.phpt | 4 ++-- Zend/tests/lazy_objects/init_trigger_debug_zval_dump.phpt | 4 ++-- Zend/tests/lazy_objects/init_trigger_foreach.phpt | 4 ++-- .../init_trigger_get_mangled_object_vars.phpt | 4 ++-- Zend/tests/lazy_objects/init_trigger_get_object_vars.phpt | 4 ++-- Zend/tests/lazy_objects/init_trigger_json_encode.phpt | 4 ++-- .../init_trigger_reflection_object_toString.phpt | 4 ++-- Zend/tests/lazy_objects/init_trigger_serialize.phpt | 4 ++-- Zend/tests/lazy_objects/init_trigger_var_dump.phpt | 4 ++-- .../init_trigger_var_dump_debug_info_001.phpt | 4 ++-- .../init_trigger_var_dump_debug_info_002.phpt | 4 ++-- Zend/tests/lazy_objects/init_trigger_var_export.phpt | 4 ++-- Zend/tests/lazy_objects/initializeLazyObject.phpt | 4 ++-- Zend/tests/lazy_objects/initializeLazyObject_error.phpt | 4 ++-- .../initializeLazyObject_noop_on_initialized_object.phpt | 4 ++-- .../initializer_must_return_the_right_type.phpt | 4 ++-- Zend/tests/lazy_objects/isset_hooked_may_initialize.phpt | 4 ++-- .../lazy_objects/isset_hooked_may_not_initialize.phpt | 4 ++-- Zend/tests/lazy_objects/isset_initializes.phpt | 4 ++-- Zend/tests/lazy_objects/markLazyObjectAsInitialized.phpt | 4 ++-- Zend/tests/lazy_objects/realize.phpt | 4 ++-- Zend/tests/lazy_objects/realize_no_props.phpt | 4 ++-- Zend/tests/lazy_objects/realize_proxy_overridden.phpt | 4 ++-- Zend/tests/lazy_objects/realize_skipped.phpt | 4 ++-- .../lazy_objects/reset_as_lazy_already_exception.phpt | 4 ++-- .../lazy_objects/reset_as_lazy_calls_destructor.phpt | 4 ++-- .../reset_as_lazy_deletes_reference_source_type.phpt | 4 ++-- .../lazy_objects/reset_as_lazy_destructor_exception.phpt | 4 ++-- .../lazy_objects/reset_as_lazy_may_skip_destructor.phpt | 4 ++-- .../lazy_objects/reset_as_lazy_resets_dynamic_props.phpt | 4 ++-- .../serialize___serialize_may_initialize.phpt | 4 ++-- .../serialize___serialize_may_not_initialize.phpt | 4 ++-- .../tests/lazy_objects/serialize___sleep_initializes.phpt | 4 ++-- Zend/tests/lazy_objects/serialize___sleep_skip_flag.phpt | 4 ++-- .../serialize___sleep_skip_flag_may_initialize.phpt | 4 ++-- Zend/tests/lazy_objects/serialize_hook.phpt | 4 ++-- Zend/tests/lazy_objects/serialize_initializes.phpt | 4 ++-- Zend/tests/lazy_objects/serialize_props_ht.phpt | 4 ++-- Zend/tests/lazy_objects/serialize_skip_flag.phpt | 4 ++-- Zend/tests/lazy_objects/serialize_skip_flag_props_ht.phpt | 4 ++-- Zend/tests/lazy_objects/skipLazyInitialization.phpt | 4 ++-- Zend/tests/lazy_objects/support_no_internal_classes.phpt | 4 ++-- .../lazy_objects/support_no_internal_sub_classes.phpt | 4 ++-- Zend/tests/lazy_objects/support_readonly_class.phpt | 4 ++-- Zend/tests/lazy_objects/support_readonly_prop.phpt | 4 ++-- Zend/tests/lazy_objects/support_stdClass.phpt | 4 ++-- Zend/tests/lazy_objects/support_stdClass_sub_classes.phpt | 4 ++-- Zend/tests/lazy_objects/unset_defined_no_initialize.phpt | 4 ++-- Zend/tests/lazy_objects/unset_hook.phpt | 4 ++-- .../lazy_objects/unset_magic_circular_may_initialize.phpt | 4 ++-- Zend/tests/lazy_objects/unset_magic_may_initialize.phpt | 4 ++-- .../lazy_objects/unset_magic_may_not_initialize.phpt | 4 ++-- Zend/tests/lazy_objects/unset_skipped_no_initialize.phpt | 4 ++-- .../lazy_objects/unset_undefined_dynamic_initializes.phpt | 4 ++-- .../unset_undefined_dynamic_initializes_no_props_ht.phpt | 4 ++-- Zend/tests/lazy_objects/unset_undefined_initializes.phpt | 4 ++-- Zend/tests/lazy_objects/write_dynamic_initializes.phpt | 4 ++-- Zend/tests/lazy_objects/write_initializes.phpt | 4 ++-- .../lazy_objects/write_magic_circular_may_initialize.phpt | 4 ++-- Zend/tests/lazy_objects/write_magic_may_initialize.phpt | 4 ++-- Zend/tests/lazy_objects/write_skipped_no_initialize.phpt | 4 ++-- 100 files changed, 219 insertions(+), 219 deletions(-) diff --git a/Zend/tests/lazy_objects/clone_calls___clone_once.phpt b/Zend/tests/lazy_objects/clone_calls___clone_once.phpt index f2af4b241250e..c0f91e3e27a42 100644 --- a/Zend/tests/lazy_objects/clone_calls___clone_once.phpt +++ b/Zend/tests/lazy_objects/clone_calls___clone_once.phpt @@ -40,7 +40,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -56,7 +56,7 @@ object(C)#%d (1) { ["a"]=> int(1) } -# Virtual: +# Proxy: string(11) "initializer" string(5) "clone" bool(false) diff --git a/Zend/tests/lazy_objects/clone_initialized.phpt b/Zend/tests/lazy_objects/clone_initialized.phpt index 30f802a7fd5f3..9540a0f960964 100644 --- a/Zend/tests/lazy_objects/clone_initialized.phpt +++ b/Zend/tests/lazy_objects/clone_initialized.phpt @@ -38,7 +38,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -53,7 +53,7 @@ object(C)#%d (1) { ["a"]=> int(1) } -# Virtual: +# Proxy: string(11) "initializer" bool(false) lazy proxy object(C)#%d (1) { diff --git a/Zend/tests/lazy_objects/clone_initializer_exception.phpt b/Zend/tests/lazy_objects/clone_initializer_exception.phpt index 8334e6eadd84e..72069ca650d12 100644 --- a/Zend/tests/lazy_objects/clone_initializer_exception.phpt +++ b/Zend/tests/lazy_objects/clone_initializer_exception.phpt @@ -41,7 +41,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { throw new \Exception('initializer'); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -49,7 +49,7 @@ Exception: initializer bool(true) lazy ghost object(C)#%d (0) { } -# Virtual: +# Proxy: Exception: initializer bool(true) lazy proxy object(C)#%d (0) { diff --git a/Zend/tests/lazy_objects/clone_initializes.phpt b/Zend/tests/lazy_objects/clone_initializes.phpt index c7ca01ba1168b..54be97fd768aa 100644 --- a/Zend/tests/lazy_objects/clone_initializes.phpt +++ b/Zend/tests/lazy_objects/clone_initializes.phpt @@ -36,7 +36,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -51,7 +51,7 @@ object(C)#%d (1) { ["a"]=> int(1) } -# Virtual: +# Proxy: string(11) "initializer" bool(false) lazy proxy object(C)#%d (1) { diff --git a/Zend/tests/lazy_objects/dtor_called_if_init.phpt b/Zend/tests/lazy_objects/dtor_called_if_init.phpt index 4002a66a13c36..19a9c7b941b00 100644 --- a/Zend/tests/lazy_objects/dtor_called_if_init.phpt +++ b/Zend/tests/lazy_objects/dtor_called_if_init.phpt @@ -25,10 +25,10 @@ function ghost() { var_dump($obj->a); } -function virtual() { +function proxy() { $reflector = new ReflectionClass(C::class); - print "# Virtual:\n"; + print "# Proxy:\n"; print "In makeLazy\n"; $obj = $reflector->newLazyProxy(function () { @@ -41,7 +41,7 @@ function virtual() { } ghost(); -virtual(); +proxy(); --EXPECTF-- # Ghost: @@ -54,7 +54,7 @@ object(C)#%d (1) { ["a"]=> int(1) } -# Virtual: +# Proxy: In makeLazy After makeLazy string(11) "initializer" diff --git a/Zend/tests/lazy_objects/dtor_not_called_if_not_init.phpt b/Zend/tests/lazy_objects/dtor_not_called_if_not_init.phpt index 17855588ec1fc..f0ea2fdfc1ba2 100644 --- a/Zend/tests/lazy_objects/dtor_not_called_if_not_init.phpt +++ b/Zend/tests/lazy_objects/dtor_not_called_if_not_init.phpt @@ -23,7 +23,7 @@ print "After newLazyGhost\n"; // Does not call destructor $obj = null; -print "# Virtual:\n"; +print "# Proxy:\n"; print "In newLazyProxy\n"; $obj = $reflector->newLazyProxy(function () { @@ -38,6 +38,6 @@ $obj = null; # Ghost: In newLazyGhost After newLazyGhost -# Virtual: +# Proxy: In newLazyProxy After newLazyGhost diff --git a/Zend/tests/lazy_objects/fetch_coalesce_initializes.phpt b/Zend/tests/lazy_objects/fetch_coalesce_initializes.phpt index 832fc7f4f64bd..f2a4123c1b2ac 100644 --- a/Zend/tests/lazy_objects/fetch_coalesce_initializes.phpt +++ b/Zend/tests/lazy_objects/fetch_coalesce_initializes.phpt @@ -32,7 +32,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: lazy ghost object(C)#%d (0) { @@ -46,7 +46,7 @@ object(C)#%d (1) { ["a"]=> int(1) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["a"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/fetch_coalesce_non_existing_initializes.phpt b/Zend/tests/lazy_objects/fetch_coalesce_non_existing_initializes.phpt index 5ed1e27133618..1ac947f93d65e 100644 --- a/Zend/tests/lazy_objects/fetch_coalesce_non_existing_initializes.phpt +++ b/Zend/tests/lazy_objects/fetch_coalesce_non_existing_initializes.phpt @@ -32,7 +32,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: lazy ghost object(C)#%d (0) { @@ -46,7 +46,7 @@ object(C)#%d (1) { ["a"]=> int(1) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["a"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/fetch_declared_prop_initializes.phpt b/Zend/tests/lazy_objects/fetch_declared_prop_initializes.phpt index 7b055c060ae3d..da3540bacc578 100644 --- a/Zend/tests/lazy_objects/fetch_declared_prop_initializes.phpt +++ b/Zend/tests/lazy_objects/fetch_declared_prop_initializes.phpt @@ -36,7 +36,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(1); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -53,7 +53,7 @@ object(C)#%d (2) { ["b"]=> int(2) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["b"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/fetch_dynamic_prop_initializes.phpt b/Zend/tests/lazy_objects/fetch_dynamic_prop_initializes.phpt index dc4d92d2965dd..a8171bcd6eb6c 100644 --- a/Zend/tests/lazy_objects/fetch_dynamic_prop_initializes.phpt +++ b/Zend/tests/lazy_objects/fetch_dynamic_prop_initializes.phpt @@ -33,7 +33,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -48,7 +48,7 @@ object(C)#%d (0) { ["a"]=> uninitialized(int) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["a"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/fetch_hook_may_not_initialize.phpt b/Zend/tests/lazy_objects/fetch_hook_may_not_initialize.phpt index b87134fff0934..b81635dfb9c84 100644 --- a/Zend/tests/lazy_objects/fetch_hook_may_not_initialize.phpt +++ b/Zend/tests/lazy_objects/fetch_hook_may_not_initialize.phpt @@ -39,7 +39,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(1); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -56,7 +56,7 @@ object(C)#%d (2) { ["b"]=> int(2) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["b"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/fetch_hook_virtual_may_initialize.phpt b/Zend/tests/lazy_objects/fetch_hook_virtual_may_initialize.phpt index a81f52795966e..f66f9a34a680b 100644 --- a/Zend/tests/lazy_objects/fetch_hook_virtual_may_initialize.phpt +++ b/Zend/tests/lazy_objects/fetch_hook_virtual_may_initialize.phpt @@ -40,7 +40,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(1); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -57,7 +57,7 @@ object(C)#%d (2) { ["b"]=> int(2) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["b"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/fetch_hook_virtual_may_not_initialize.phpt b/Zend/tests/lazy_objects/fetch_hook_virtual_may_not_initialize.phpt index cd9a1d837c95e..adf3c2845f21a 100644 --- a/Zend/tests/lazy_objects/fetch_hook_virtual_may_not_initialize.phpt +++ b/Zend/tests/lazy_objects/fetch_hook_virtual_may_not_initialize.phpt @@ -37,7 +37,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(1); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -50,7 +50,7 @@ lazy ghost object(C)#%d (0) { ["b"]=> uninitialized(int) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["b"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/fetch_magic_prop_may_initialize.phpt b/Zend/tests/lazy_objects/fetch_magic_prop_may_initialize.phpt index cff2e62d1bb47..491b26dbbee82 100644 --- a/Zend/tests/lazy_objects/fetch_magic_prop_may_initialize.phpt +++ b/Zend/tests/lazy_objects/fetch_magic_prop_may_initialize.phpt @@ -35,7 +35,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: lazy ghost object(C)#%d (0) { @@ -49,7 +49,7 @@ object(C)#%d (1) { ["a"]=> int(1) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["a"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/fetch_magic_prop_may_not_initialize.phpt b/Zend/tests/lazy_objects/fetch_magic_prop_may_not_initialize.phpt index bc362abf02831..3cd283705ab2b 100644 --- a/Zend/tests/lazy_objects/fetch_magic_prop_may_not_initialize.phpt +++ b/Zend/tests/lazy_objects/fetch_magic_prop_may_not_initialize.phpt @@ -35,7 +35,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -48,7 +48,7 @@ lazy ghost object(C)#%d (0) { ["a"]=> uninitialized(int) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["a"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/fetch_magic_prop_recursive_may_initialize.phpt b/Zend/tests/lazy_objects/fetch_magic_prop_recursive_may_initialize.phpt index c1c9dcb1cfe42..db605826f64e5 100644 --- a/Zend/tests/lazy_objects/fetch_magic_prop_recursive_may_initialize.phpt +++ b/Zend/tests/lazy_objects/fetch_magic_prop_recursive_may_initialize.phpt @@ -35,7 +35,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: lazy ghost object(C)#%d (0) { @@ -51,7 +51,7 @@ object(C)#%d (1) { ["a"]=> int(1) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["a"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/fetch_op_dynamic_error.phpt b/Zend/tests/lazy_objects/fetch_op_dynamic_error.phpt index 1efd76071224a..f6f4cddedc63e 100644 --- a/Zend/tests/lazy_objects/fetch_op_dynamic_error.phpt +++ b/Zend/tests/lazy_objects/fetch_op_dynamic_error.phpt @@ -37,7 +37,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { throw new Error("initializer"); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -50,7 +50,7 @@ lazy ghost object(C)#%d (0) { ["a"]=> uninitialized(int) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["a"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/fetch_op_dynamic_prop_initializes.phpt b/Zend/tests/lazy_objects/fetch_op_dynamic_prop_initializes.phpt index e52e3c8cdf184..3f9af1aa5f1dd 100644 --- a/Zend/tests/lazy_objects/fetch_op_dynamic_prop_initializes.phpt +++ b/Zend/tests/lazy_objects/fetch_op_dynamic_prop_initializes.phpt @@ -33,7 +33,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -50,7 +50,7 @@ object(C)#%d (2) { ["dynamic"]=> int(1) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["a"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/fetch_op_error.phpt b/Zend/tests/lazy_objects/fetch_op_error.phpt index 7e04d3593d527..4ccfef4ac4d3a 100644 --- a/Zend/tests/lazy_objects/fetch_op_error.phpt +++ b/Zend/tests/lazy_objects/fetch_op_error.phpt @@ -37,7 +37,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { throw new Error("initializer"); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -50,7 +50,7 @@ lazy ghost object(C)#%d (0) { ["a"]=> uninitialized(int) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["a"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/fetch_op_initializes.phpt b/Zend/tests/lazy_objects/fetch_op_initializes.phpt index 1731f7004fc75..d1a8605eb1d7f 100644 --- a/Zend/tests/lazy_objects/fetch_op_initializes.phpt +++ b/Zend/tests/lazy_objects/fetch_op_initializes.phpt @@ -33,7 +33,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -48,7 +48,7 @@ object(C)#%d (1) { ["a"]=> int(3) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["a"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/fetch_op_skipped_prop_does_not_initialize.phpt b/Zend/tests/lazy_objects/fetch_op_skipped_prop_does_not_initialize.phpt index f152366b12ca1..c1e662eaef1a3 100644 --- a/Zend/tests/lazy_objects/fetch_op_skipped_prop_does_not_initialize.phpt +++ b/Zend/tests/lazy_objects/fetch_op_skipped_prop_does_not_initialize.phpt @@ -46,7 +46,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new c(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -69,7 +69,7 @@ object(C)#%d (2) { ["c"]=> uninitialized(int) } -# Virtual: +# Proxy: object(C)#%d (2) { ["a"]=> NULL diff --git a/Zend/tests/lazy_objects/fetch_ref_initializes.phpt b/Zend/tests/lazy_objects/fetch_ref_initializes.phpt index 6c7c28cee5084..e1289558aaa77 100644 --- a/Zend/tests/lazy_objects/fetch_ref_initializes.phpt +++ b/Zend/tests/lazy_objects/fetch_ref_initializes.phpt @@ -33,7 +33,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -48,7 +48,7 @@ object(C)#%d (1) { ["a"]=> &int(1) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["a"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/fetch_ref_skipped_prop_does_not_initialize.phpt b/Zend/tests/lazy_objects/fetch_ref_skipped_prop_does_not_initialize.phpt index 26a820cbb092a..c64cd88781a31 100644 --- a/Zend/tests/lazy_objects/fetch_ref_skipped_prop_does_not_initialize.phpt +++ b/Zend/tests/lazy_objects/fetch_ref_skipped_prop_does_not_initialize.phpt @@ -41,7 +41,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -63,7 +63,7 @@ object(C)#%d (2) { ["c"]=> uninitialized(int) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["b"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/fetch_skipped_prop_does_not_initialize.phpt b/Zend/tests/lazy_objects/fetch_skipped_prop_does_not_initialize.phpt index f210e8b05aaa7..e93a65ee87cec 100644 --- a/Zend/tests/lazy_objects/fetch_skipped_prop_does_not_initialize.phpt +++ b/Zend/tests/lazy_objects/fetch_skipped_prop_does_not_initialize.phpt @@ -48,7 +48,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(1); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -71,7 +71,7 @@ object(C)#%d (2) { ["c"]=> uninitialized(int) } -# Virtual: +# Proxy: object(C)#%d (2) { ["a"]=> NULL diff --git a/Zend/tests/lazy_objects/final_classes_can_be_initialized_lazily.phpt b/Zend/tests/lazy_objects/final_classes_can_be_initialized_lazily.phpt index 42a5177f91125..2434e69f57349 100644 --- a/Zend/tests/lazy_objects/final_classes_can_be_initialized_lazily.phpt +++ b/Zend/tests/lazy_objects/final_classes_can_be_initialized_lazily.phpt @@ -24,7 +24,7 @@ var_dump($obj); var_dump($obj->a); var_dump($obj); -print "# Virtual:\n"; +print "# Proxy:\n"; $obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); @@ -48,7 +48,7 @@ object(C)#%d (1) { ["a"]=> int(1) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["a"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/gc_001.phpt b/Zend/tests/lazy_objects/gc_001.phpt index db4ab41b8587e..7707423815a5b 100644 --- a/Zend/tests/lazy_objects/gc_001.phpt +++ b/Zend/tests/lazy_objects/gc_001.phpt @@ -26,8 +26,8 @@ function ghost() { gc_collect_cycles(); } -function virtual() { - printf("# Virtual:\n"); +function proxy() { + printf("# Proxy:\n"); $canary = new Canary(); $obj = (new ReflectionClass(C::class))->newInstanceWithoutConstructor(); @@ -42,13 +42,13 @@ function virtual() { } ghost(); -virtual(); +proxy(); ?> ==DONE== --EXPECT-- # Ghost: string(10) "__destruct" -# Virtual: +# Proxy: string(10) "__destruct" ==DONE== diff --git a/Zend/tests/lazy_objects/gc_002.phpt b/Zend/tests/lazy_objects/gc_002.phpt index 004907c483adb..c794e4077c2bc 100644 --- a/Zend/tests/lazy_objects/gc_002.phpt +++ b/Zend/tests/lazy_objects/gc_002.phpt @@ -29,8 +29,8 @@ function ghost() { gc_collect_cycles(); } -function virtual() { - printf("# Virtual:\n"); +function proxy() { + printf("# Proxy:\n"); $canary = new Canary(); @@ -47,13 +47,13 @@ function virtual() { } ghost(); -virtual(); +proxy(); ?> ==DONE== --EXPECT-- # Ghost: string(10) "__destruct" -# Virtual: +# Proxy: string(10) "__destruct" ==DONE== diff --git a/Zend/tests/lazy_objects/gc_003.phpt b/Zend/tests/lazy_objects/gc_003.phpt index a17765a503d7a..ce58398e509e3 100644 --- a/Zend/tests/lazy_objects/gc_003.phpt +++ b/Zend/tests/lazy_objects/gc_003.phpt @@ -29,8 +29,8 @@ function ghost() { gc_collect_cycles(); } -function virtual() { - printf("# Virtual:\n"); +function proxy() { + printf("# Proxy:\n"); $canary = new Canary(); @@ -47,13 +47,13 @@ function virtual() { } ghost(); -virtual(); +proxy(); ?> ==DONE== --EXPECT-- # Ghost: string(10) "__destruct" -# Virtual: +# Proxy: string(10) "__destruct" ==DONE== diff --git a/Zend/tests/lazy_objects/gc_004.phpt b/Zend/tests/lazy_objects/gc_004.phpt index f0e64f39de698..ab0b5c2996770 100644 --- a/Zend/tests/lazy_objects/gc_004.phpt +++ b/Zend/tests/lazy_objects/gc_004.phpt @@ -31,8 +31,8 @@ function ghost() { gc_collect_cycles(); } -function virtual() { - printf("# Virtual:\n"); +function proxy() { + printf("# Proxy:\n"); $canary = new Canary(); @@ -51,7 +51,7 @@ function virtual() { } ghost(); -virtual(); +proxy(); ?> ==DONE== @@ -60,7 +60,7 @@ virtual(); object(C)#%d (0) { } string(10) "__destruct" -# Virtual: +# Proxy: object(C)#%d (0) { } string(10) "__destruct" diff --git a/Zend/tests/lazy_objects/gc_005.phpt b/Zend/tests/lazy_objects/gc_005.phpt index 70a20759248bf..934439adab951 100644 --- a/Zend/tests/lazy_objects/gc_005.phpt +++ b/Zend/tests/lazy_objects/gc_005.phpt @@ -34,8 +34,8 @@ function ghost() { gc_collect_cycles(); } -function virtual() { - printf("# Virtual:\n"); +function proxy() { + printf("# Proxy:\n"); $canary = new Canary(); @@ -56,13 +56,13 @@ function virtual() { } ghost(); -virtual(); +proxy(); ?> ==DONE== --EXPECT-- # Ghost: string(10) "__destruct" -# Virtual: +# Proxy: string(10) "__destruct" ==DONE== diff --git a/Zend/tests/lazy_objects/init_exception_leaves_object_lazy.phpt b/Zend/tests/lazy_objects/init_exception_leaves_object_lazy.phpt index a25517ea16004..86ecc2c9b8e2e 100644 --- a/Zend/tests/lazy_objects/init_exception_leaves_object_lazy.phpt +++ b/Zend/tests/lazy_objects/init_exception_leaves_object_lazy.phpt @@ -40,14 +40,14 @@ $obj = $reflector->newLazyProxy(function ($obj) { throw new Exception('initializer exception'); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECT-- # Ghost: string(11) "initializer" initializer exception Is lazy: 1 -# Virtual: +# Proxy: string(11) "initializer" initializer exception Is lazy: 1 diff --git a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes.phpt b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes.phpt index 2bc098a8d19ee..4edf9481ebc22 100644 --- a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes.phpt +++ b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes.phpt @@ -46,8 +46,8 @@ $obj = $reflector->newLazyProxy(function ($obj) { throw new Exception('initializer exception'); }); -// Initializer effects on the virtual proxy are not reverted -test('Virtual', $obj); +// Initializer effects on the proxy are not reverted +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -60,7 +60,7 @@ lazy ghost object(C)#%d (1) { int(0) } Is lazy: 1 -# Virtual: +# Proxy: string(11) "initializer" initializer exception lazy proxy object(C)#%d (3) { diff --git a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props.phpt b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props.phpt index ba91c973a11d0..ce94fc8b2ab79 100644 --- a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props.phpt +++ b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props.phpt @@ -49,8 +49,8 @@ $obj = $reflector->newLazyProxy(function ($obj) { throw new Exception('initializer exception'); }); -// Initializer effects on the virtual proxy are not reverted -test('Virtual', $obj); +// Initializer effects on the proxy are not reverted +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -63,7 +63,7 @@ lazy ghost object(C)#%d (1) { int(0) } Is lazy: 1 -# Virtual: +# Proxy: string(11) "initializer" initializer exception lazy proxy object(C)#%d (4) { diff --git a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props_and_ht.phpt b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props_and_ht.phpt index 7de4025dcee94..1bc3eb2cea8e1 100644 --- a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props_and_ht.phpt +++ b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props_and_ht.phpt @@ -52,8 +52,8 @@ $obj = $reflector->newLazyProxy(function ($obj) { throw new Exception('initializer exception'); }); -// Initializer effects on the virtual proxy are not reverted -test('Virtual', $obj); +// Initializer effects on the proxy are not reverted +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -68,7 +68,7 @@ lazy ghost object(C)#%d (1) { int(0) } Is lazy: 1 -# Virtual: +# Proxy: array(0) { } string(11) "initializer" diff --git a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_overridden_prop.phpt b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_overridden_prop.phpt index 8127f7f138942..656d267e137fa 100644 --- a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_overridden_prop.phpt +++ b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_overridden_prop.phpt @@ -47,14 +47,14 @@ $obj = $reflector->newLazyProxy(function ($obj) { throw new Exception('initializer exception'); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECT-- # Ghost: string(11) "initializer" initializer exception Is lazy: 1 -# Virtual: +# Proxy: string(11) "initializer" initializer exception Is lazy: 1 diff --git a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht.phpt b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht.phpt index 081a4d2737f48..c4f0bd98773fd 100644 --- a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht.phpt +++ b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht.phpt @@ -49,8 +49,8 @@ $obj = $reflector->newLazyProxy(function ($obj) { throw new Exception('initializer exception'); }); -// Initializer effects on the virtual proxy are not reverted -test('Virtual', $obj); +// Initializer effects on the proxy are not reverted +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -67,7 +67,7 @@ lazy ghost object(C)#%d (1) { int(0) } Is lazy: 1 -# Virtual: +# Proxy: array(1) { ["c"]=> int(0) diff --git a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht_ref.phpt b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht_ref.phpt index f3d4285f55257..094f5c9b80947 100644 --- a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht_ref.phpt +++ b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht_ref.phpt @@ -55,8 +55,8 @@ $obj = $reflector->newLazyProxy(function ($obj) { throw new Exception('initializer exception'); }); -// Initializer effects on the virtual proxy are not reverted -test('Virtual', $obj); +// Initializer effects on the proxy are not reverted +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -76,7 +76,7 @@ Is lazy: 1 Warning: Undefined variable $table in %s on line %d NULL -# Virtual: +# Proxy: array(1) { ["c"]=> int(0) diff --git a/Zend/tests/lazy_objects/init_handles_ref_source_types.phpt b/Zend/tests/lazy_objects/init_handles_ref_source_types.phpt index 1042131ec3165..366751e02d7bb 100644 --- a/Zend/tests/lazy_objects/init_handles_ref_source_types.phpt +++ b/Zend/tests/lazy_objects/init_handles_ref_source_types.phpt @@ -29,7 +29,7 @@ function test(string $name, object $obj) { var_dump($obj); try { - // $refA retained its reference source type (except for the virtual + // $refA retained its reference source type (except for the proxy // case: its the responsibility of the initializer to propagate // pre-initialized properties to the instance) $refA = 1; @@ -58,7 +58,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(null); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: lazy ghost object(C)#%d (2) { @@ -78,7 +78,7 @@ object(C)#%d (3) { NULL } TypeError: Cannot assign int to reference held by property C::$a of type ?C -# Virtual: +# Proxy: lazy proxy object(C)#%d (2) { ["a"]=> &NULL diff --git a/Zend/tests/lazy_objects/init_handles_ref_source_types_exception.phpt b/Zend/tests/lazy_objects/init_handles_ref_source_types_exception.phpt index d2caad0ccd84e..0613ca5f3f44d 100644 --- a/Zend/tests/lazy_objects/init_handles_ref_source_types_exception.phpt +++ b/Zend/tests/lazy_objects/init_handles_ref_source_types_exception.phpt @@ -32,7 +32,7 @@ function test(string $name, object $obj) { var_dump($obj); try { - // $refA retained its reference source type (except for the virtual + // $refA retained its reference source type (except for the proxy // case: it is the responsibility of the initializer to propagate // pre-initialized properties to the instance) $refA = 1; @@ -71,7 +71,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(null); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: lazy ghost object(C)#%d (2) { @@ -90,7 +90,7 @@ lazy ghost object(C)#%d (2) { } TypeError: Cannot assign int to reference held by property C::$a of type ?C TypeError: Cannot assign int to reference held by property C::$b of type ?C -# Virtual: +# Proxy: lazy proxy object(C)#%d (2) { ["a"]=> &NULL diff --git a/Zend/tests/lazy_objects/init_trigger_array_cast.phpt b/Zend/tests/lazy_objects/init_trigger_array_cast.phpt index e58e1cbbd775a..d48633f33dfad 100644 --- a/Zend/tests/lazy_objects/init_trigger_array_cast.phpt +++ b/Zend/tests/lazy_objects/init_trigger_array_cast.phpt @@ -25,7 +25,7 @@ var_dump((array)$obj); $obj->a = 2; var_dump((array)$obj); -print "# Virtual:\n"; +print "# Proxy:\n"; $obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); @@ -47,7 +47,7 @@ array(1) { ["a"]=> int(2) } -# Virtual: +# Proxy: array(0) { } string(11) "initializer" diff --git a/Zend/tests/lazy_objects/init_trigger_debug_zval_dump.phpt b/Zend/tests/lazy_objects/init_trigger_debug_zval_dump.phpt index 0909942bcb284..b755484c15d93 100644 --- a/Zend/tests/lazy_objects/init_trigger_debug_zval_dump.phpt +++ b/Zend/tests/lazy_objects/init_trigger_debug_zval_dump.phpt @@ -24,7 +24,7 @@ debug_zval_dump($obj); $reflector->initializeLazyObject($obj); debug_zval_dump($obj); -print "# Virtual:\n"; +print "# Proxy:\n"; $obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); @@ -47,7 +47,7 @@ object(C)#%d (1) refcount(2){ ["a"]=> int(1) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) refcount(2){ ["a"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/init_trigger_foreach.phpt b/Zend/tests/lazy_objects/init_trigger_foreach.phpt index dd5c8b6291433..b8bd780666bb8 100644 --- a/Zend/tests/lazy_objects/init_trigger_foreach.phpt +++ b/Zend/tests/lazy_objects/init_trigger_foreach.phpt @@ -24,7 +24,7 @@ foreach ($obj as $prop => $value) { var_dump($prop, $value); } -print "# Virtual:\n"; +print "# Proxy:\n"; $obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); @@ -41,7 +41,7 @@ string(11) "initializer" string(14) "C::__construct" string(1) "a" int(1) -# Virtual: +# Proxy: string(11) "initializer" string(14) "C::__construct" string(1) "a" diff --git a/Zend/tests/lazy_objects/init_trigger_get_mangled_object_vars.phpt b/Zend/tests/lazy_objects/init_trigger_get_mangled_object_vars.phpt index ccac68990820c..aff038fcda25f 100644 --- a/Zend/tests/lazy_objects/init_trigger_get_mangled_object_vars.phpt +++ b/Zend/tests/lazy_objects/init_trigger_get_mangled_object_vars.phpt @@ -34,7 +34,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: array(0) { @@ -45,7 +45,7 @@ array(1) { ["a"]=> int(2) } -# Virtual: +# Proxy: array(0) { } string(11) "initializer" diff --git a/Zend/tests/lazy_objects/init_trigger_get_object_vars.phpt b/Zend/tests/lazy_objects/init_trigger_get_object_vars.phpt index 19b2ad936299c..ca14328377488 100644 --- a/Zend/tests/lazy_objects/init_trigger_get_object_vars.phpt +++ b/Zend/tests/lazy_objects/init_trigger_get_object_vars.phpt @@ -25,7 +25,7 @@ var_dump(get_object_vars($obj)); $obj->a = 2; var_dump(get_object_vars($obj)); -print "# Virtual:\n"; +print "# Proxy:\n"; $obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); @@ -49,7 +49,7 @@ array(1) { ["a"]=> int(2) } -# Virtual: +# Proxy: string(11) "initializer" string(14) "C::__construct" array(1) { diff --git a/Zend/tests/lazy_objects/init_trigger_json_encode.phpt b/Zend/tests/lazy_objects/init_trigger_json_encode.phpt index 02b2331fcdb38..c7c7aed99f1ce 100644 --- a/Zend/tests/lazy_objects/init_trigger_json_encode.phpt +++ b/Zend/tests/lazy_objects/init_trigger_json_encode.phpt @@ -22,7 +22,7 @@ $obj = $reflector->newLazyGhost(function ($obj) { var_dump(json_encode($obj)); -print "# Virtual:\n"; +print "# Proxy:\n"; $obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); @@ -36,7 +36,7 @@ var_dump(json_encode($obj)); string(11) "initializer" string(14) "C::__construct" string(7) "{"a":1}" -# Virtual: +# Proxy: string(11) "initializer" string(14) "C::__construct" string(7) "{"a":1}" diff --git a/Zend/tests/lazy_objects/init_trigger_reflection_object_toString.phpt b/Zend/tests/lazy_objects/init_trigger_reflection_object_toString.phpt index dbf16348d83b7..7f0cc6e4ff543 100644 --- a/Zend/tests/lazy_objects/init_trigger_reflection_object_toString.phpt +++ b/Zend/tests/lazy_objects/init_trigger_reflection_object_toString.phpt @@ -34,12 +34,12 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECT-- # Ghost Initialized: bool(false) -# Virtual +# Proxy Initialized: bool(false) diff --git a/Zend/tests/lazy_objects/init_trigger_serialize.phpt b/Zend/tests/lazy_objects/init_trigger_serialize.phpt index a14edded5ae16..5a5e2f78f66b7 100644 --- a/Zend/tests/lazy_objects/init_trigger_serialize.phpt +++ b/Zend/tests/lazy_objects/init_trigger_serialize.phpt @@ -22,7 +22,7 @@ $obj = $reflector->newLazyGhost(function ($obj) { var_dump(serialize($obj)); -print "# Virtual:\n"; +print "# Proxy:\n"; $obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); @@ -37,7 +37,7 @@ var_dump(serialize($obj)); string(11) "initializer" string(14) "C::__construct" string(24) "O:1:"C":1:{s:1:"a";i:1;}" -# Virtual: +# Proxy: string(11) "initializer" string(14) "C::__construct" string(24) "O:1:"C":1:{s:1:"a";i:1;}" diff --git a/Zend/tests/lazy_objects/init_trigger_var_dump.phpt b/Zend/tests/lazy_objects/init_trigger_var_dump.phpt index 30ece89208fa6..17dbe62cae6eb 100644 --- a/Zend/tests/lazy_objects/init_trigger_var_dump.phpt +++ b/Zend/tests/lazy_objects/init_trigger_var_dump.phpt @@ -24,7 +24,7 @@ var_dump($obj); $reflector->initializeLazyObject($obj); var_dump($obj); -print "# Virtual:\n"; +print "# Proxy:\n"; $obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); @@ -47,7 +47,7 @@ object(C)#%d (1) { ["a"]=> int(1) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["a"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/init_trigger_var_dump_debug_info_001.phpt b/Zend/tests/lazy_objects/init_trigger_var_dump_debug_info_001.phpt index f752815f8e8b3..0fbcaf826e305 100644 --- a/Zend/tests/lazy_objects/init_trigger_var_dump_debug_info_001.phpt +++ b/Zend/tests/lazy_objects/init_trigger_var_dump_debug_info_001.phpt @@ -38,7 +38,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost @@ -48,7 +48,7 @@ lazy ghost object(C)#%d (1) { } Initialized: bool(false) -# Virtual +# Proxy lazy proxy object(C)#%d (1) { [0]=> string(5) "hello" diff --git a/Zend/tests/lazy_objects/init_trigger_var_dump_debug_info_002.phpt b/Zend/tests/lazy_objects/init_trigger_var_dump_debug_info_002.phpt index 7ec224e7b6b59..54ebf1a80aaa3 100644 --- a/Zend/tests/lazy_objects/init_trigger_var_dump_debug_info_002.phpt +++ b/Zend/tests/lazy_objects/init_trigger_var_dump_debug_info_002.phpt @@ -37,7 +37,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost @@ -49,7 +49,7 @@ object(C)#%d (1) { } Initialized: bool(true) -# Virtual +# Proxy string(11) "initializer" string(14) "C::__construct" lazy proxy object(C)#%d (1) { diff --git a/Zend/tests/lazy_objects/init_trigger_var_export.phpt b/Zend/tests/lazy_objects/init_trigger_var_export.phpt index 315235d5fb379..55d45063646dd 100644 --- a/Zend/tests/lazy_objects/init_trigger_var_export.phpt +++ b/Zend/tests/lazy_objects/init_trigger_var_export.phpt @@ -23,7 +23,7 @@ $obj = $reflector->newLazyGhost(function ($obj) { var_export($obj); print "\n"; -print "# Virtual:\n"; +print "# Proxy:\n"; $obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); @@ -39,7 +39,7 @@ string(14) "C::__construct" \C::__set_state(array( 'a' => 1, )) -# Virtual: +# Proxy: string(11) "initializer" string(14) "C::__construct" \C::__set_state(array( diff --git a/Zend/tests/lazy_objects/initializeLazyObject.phpt b/Zend/tests/lazy_objects/initializeLazyObject.phpt index d1770c2c083a3..b53858a76a207 100644 --- a/Zend/tests/lazy_objects/initializeLazyObject.phpt +++ b/Zend/tests/lazy_objects/initializeLazyObject.phpt @@ -37,7 +37,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return $c; }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -50,7 +50,7 @@ object(C)#%d (1) { } Initialized: bool(true) -# Virtual: +# Proxy: Initialized: bool(false) string(11) "initializer" diff --git a/Zend/tests/lazy_objects/initializeLazyObject_error.phpt b/Zend/tests/lazy_objects/initializeLazyObject_error.phpt index e81762a4dd748..541d6a8c491f1 100644 --- a/Zend/tests/lazy_objects/initializeLazyObject_error.phpt +++ b/Zend/tests/lazy_objects/initializeLazyObject_error.phpt @@ -36,7 +36,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { throw new \Exception('initializer exception'); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECT-- # Ghost: @@ -44,7 +44,7 @@ bool(false) string(11) "initializer" initializer exception bool(false) -# Virtual: +# Proxy: bool(false) string(11) "initializer" initializer exception diff --git a/Zend/tests/lazy_objects/initializeLazyObject_noop_on_initialized_object.phpt b/Zend/tests/lazy_objects/initializeLazyObject_noop_on_initialized_object.phpt index 266e92cbc4b19..c424d2ecd396d 100644 --- a/Zend/tests/lazy_objects/initializeLazyObject_noop_on_initialized_object.phpt +++ b/Zend/tests/lazy_objects/initializeLazyObject_noop_on_initialized_object.phpt @@ -37,7 +37,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return $c; }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -49,7 +49,7 @@ object(C)#%d (1) { int(1) } bool(true) -# Virtual: +# Proxy: string(11) "initializer" int(1) bool(true) diff --git a/Zend/tests/lazy_objects/initializer_must_return_the_right_type.phpt b/Zend/tests/lazy_objects/initializer_must_return_the_right_type.phpt index 54f5b79decf6e..dd68a88406eeb 100644 --- a/Zend/tests/lazy_objects/initializer_must_return_the_right_type.phpt +++ b/Zend/tests/lazy_objects/initializer_must_return_the_right_type.phpt @@ -42,7 +42,7 @@ try { } var_dump($obj); -print "# Virtual initializer must return an instance of a compatible class:\n"; +print "# Proxy initializer must return an instance of a compatible class:\n"; print "## Valid cases:\n"; $tests = [ @@ -111,7 +111,7 @@ lazy ghost object(C)#%d (0) { ["b"]=> uninitialized(int) } -# Virtual initializer must return an instance of a compatible class: +# Proxy initializer must return an instance of a compatible class: ## Valid cases: ## C vs C string(11) "initializer" diff --git a/Zend/tests/lazy_objects/isset_hooked_may_initialize.phpt b/Zend/tests/lazy_objects/isset_hooked_may_initialize.phpt index ef4deb1a952f9..3bdb63c3166b9 100644 --- a/Zend/tests/lazy_objects/isset_hooked_may_initialize.phpt +++ b/Zend/tests/lazy_objects/isset_hooked_may_initialize.phpt @@ -39,7 +39,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(1); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -56,7 +56,7 @@ object(C)#%d (2) { ["b"]=> int(2) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["b"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/isset_hooked_may_not_initialize.phpt b/Zend/tests/lazy_objects/isset_hooked_may_not_initialize.phpt index 18d420064f72d..35f15be1007c3 100644 --- a/Zend/tests/lazy_objects/isset_hooked_may_not_initialize.phpt +++ b/Zend/tests/lazy_objects/isset_hooked_may_not_initialize.phpt @@ -39,7 +39,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(1); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -52,7 +52,7 @@ lazy ghost object(C)#%d (0) { ["b"]=> uninitialized(int) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["b"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/isset_initializes.phpt b/Zend/tests/lazy_objects/isset_initializes.phpt index d70ae76ccc84e..1478bb054fce2 100644 --- a/Zend/tests/lazy_objects/isset_initializes.phpt +++ b/Zend/tests/lazy_objects/isset_initializes.phpt @@ -36,7 +36,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(1); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -53,7 +53,7 @@ object(C)#%d (2) { ["b"]=> int(2) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["b"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/markLazyObjectAsInitialized.phpt b/Zend/tests/lazy_objects/markLazyObjectAsInitialized.phpt index 72f6476bc9afa..691cba7f34f4a 100644 --- a/Zend/tests/lazy_objects/markLazyObjectAsInitialized.phpt +++ b/Zend/tests/lazy_objects/markLazyObjectAsInitialized.phpt @@ -39,7 +39,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return $c; }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -53,7 +53,7 @@ object(C)#%d (1) { ["a"]=> int(1) } -# Virtual: +# Proxy: Initialized: bool(false) markLazyObjectAsInitialized(true) returns $obj: diff --git a/Zend/tests/lazy_objects/realize.phpt b/Zend/tests/lazy_objects/realize.phpt index f57303cb4b00a..988b8114bde6f 100644 --- a/Zend/tests/lazy_objects/realize.phpt +++ b/Zend/tests/lazy_objects/realize.phpt @@ -67,7 +67,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -82,7 +82,7 @@ object(C)#%d (2) { ["a"]=> string(2) "a2" } -# Virtual: +# Proxy: bool(false) bool(false) bool(false) diff --git a/Zend/tests/lazy_objects/realize_no_props.phpt b/Zend/tests/lazy_objects/realize_no_props.phpt index 5450eda1aeba1..0344c560c8a65 100644 --- a/Zend/tests/lazy_objects/realize_no_props.phpt +++ b/Zend/tests/lazy_objects/realize_no_props.phpt @@ -53,7 +53,7 @@ $obj3 = (new ReflectionClass(C::class))->newLazyGhost(function () { var_dump("initializer"); }); -test('Virtual', $obj, $obj2, $obj3); +test('Proxy', $obj, $obj2, $obj3); --EXPECTF-- # Ghost: @@ -66,7 +66,7 @@ object(D)#%d (0) { bool(false) object(C)#%d (0) { } -# Virtual: +# Proxy: bool(false) object(C)#%d (0) { } diff --git a/Zend/tests/lazy_objects/realize_proxy_overridden.phpt b/Zend/tests/lazy_objects/realize_proxy_overridden.phpt index 9da07059b1e10..7443c7f0a66a3 100644 --- a/Zend/tests/lazy_objects/realize_proxy_overridden.phpt +++ b/Zend/tests/lazy_objects/realize_proxy_overridden.phpt @@ -62,7 +62,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -77,7 +77,7 @@ object(C)#%d (2) { ["a"]=> string(2) "a2" } -# Virtual: +# Proxy: bool(false) bool(false) bool(false) diff --git a/Zend/tests/lazy_objects/realize_skipped.phpt b/Zend/tests/lazy_objects/realize_skipped.phpt index 4d1c94a311cfe..711ccfa93c000 100644 --- a/Zend/tests/lazy_objects/realize_skipped.phpt +++ b/Zend/tests/lazy_objects/realize_skipped.phpt @@ -70,7 +70,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -86,7 +86,7 @@ object(C)#%d (0) { ["a"]=> uninitialized(string) } -# Virtual: +# Proxy: bool(false) bool(false) bool(false) diff --git a/Zend/tests/lazy_objects/reset_as_lazy_already_exception.phpt b/Zend/tests/lazy_objects/reset_as_lazy_already_exception.phpt index 7f1f25486d2b4..708855d312609 100644 --- a/Zend/tests/lazy_objects/reset_as_lazy_already_exception.phpt +++ b/Zend/tests/lazy_objects/reset_as_lazy_already_exception.phpt @@ -21,7 +21,7 @@ try { printf("%s: %s\n", $e::class, $e->getMessage()); } -printf("# Virtual:\n"); +printf("# Proxy:\n"); $obj = new C(); $reflector->resetAsLazyProxy($obj, function () {}); @@ -51,6 +51,6 @@ try { --EXPECT-- # Ghost: ReflectionException: Object is already lazy -# Virtual: +# Proxy: ReflectionException: Object is already lazy ==DONE== diff --git a/Zend/tests/lazy_objects/reset_as_lazy_calls_destructor.phpt b/Zend/tests/lazy_objects/reset_as_lazy_calls_destructor.phpt index f7ed0178a6175..733da55a5cbc5 100644 --- a/Zend/tests/lazy_objects/reset_as_lazy_calls_destructor.phpt +++ b/Zend/tests/lazy_objects/reset_as_lazy_calls_destructor.phpt @@ -30,7 +30,7 @@ print "After makeLazy\n"; var_dump($obj->a); $obj = null; -print "# Virtual:\n"; +print "# Proxy:\n"; $obj = new C(); print "In makeLazy\n"; @@ -52,7 +52,7 @@ After makeLazy string(11) "initializer" int(1) string(13) "C::__destruct" -# Virtual: +# Proxy: In makeLazy string(13) "C::__destruct" After makeLazy diff --git a/Zend/tests/lazy_objects/reset_as_lazy_deletes_reference_source_type.phpt b/Zend/tests/lazy_objects/reset_as_lazy_deletes_reference_source_type.phpt index 2af1c07f23e3c..583d5ccc881e5 100644 --- a/Zend/tests/lazy_objects/reset_as_lazy_deletes_reference_source_type.phpt +++ b/Zend/tests/lazy_objects/reset_as_lazy_deletes_reference_source_type.phpt @@ -32,7 +32,7 @@ var_dump($obj); var_dump($obj->a); var_dump($obj); -print "# Virtual:\n"; +print "# Proxy:\n"; $obj = new C(); $ref = &$obj->a; @@ -65,7 +65,7 @@ object(C)#%d (1) { ["a"]=> int(1) } -# Virtual: +# Proxy: TypeError: Cannot assign string to reference held by property C::$a of type int lazy proxy object(C)#%d (0) { ["a"]=> diff --git a/Zend/tests/lazy_objects/reset_as_lazy_destructor_exception.phpt b/Zend/tests/lazy_objects/reset_as_lazy_destructor_exception.phpt index 0a6e2977f524c..67a79ab6e8ac9 100644 --- a/Zend/tests/lazy_objects/reset_as_lazy_destructor_exception.phpt +++ b/Zend/tests/lazy_objects/reset_as_lazy_destructor_exception.phpt @@ -32,7 +32,7 @@ try { // Object was not made lazy var_dump(!$reflector->isUninitializedLazyObject($obj)); -print "# Virtual:\n"; +print "# Proxy:\n"; $obj = new C(); try { @@ -52,6 +52,6 @@ var_dump(!(new ReflectionClass($obj))->isUninitializedLazyObject($obj)); # Ghost: Exception: C::__destruct bool(true) -# Virtual: +# Proxy: Exception: C::__destruct bool(true) diff --git a/Zend/tests/lazy_objects/reset_as_lazy_may_skip_destructor.phpt b/Zend/tests/lazy_objects/reset_as_lazy_may_skip_destructor.phpt index c7e8b0b8c2ccc..d0c22a0333ff2 100644 --- a/Zend/tests/lazy_objects/reset_as_lazy_may_skip_destructor.phpt +++ b/Zend/tests/lazy_objects/reset_as_lazy_may_skip_destructor.phpt @@ -30,7 +30,7 @@ print "After makeLazy\n"; var_dump($obj->a); $obj = null; -print "# Virtual:\n"; +print "# Proxy:\n"; $obj = new C(); print "In makeLazy\n"; @@ -51,7 +51,7 @@ After makeLazy string(11) "initializer" int(1) string(13) "C::__destruct" -# Virtual: +# Proxy: In makeLazy After makeLazy string(11) "initializer" diff --git a/Zend/tests/lazy_objects/reset_as_lazy_resets_dynamic_props.phpt b/Zend/tests/lazy_objects/reset_as_lazy_resets_dynamic_props.phpt index c9a05910ae350..d99a30b3c1164 100644 --- a/Zend/tests/lazy_objects/reset_as_lazy_resets_dynamic_props.phpt +++ b/Zend/tests/lazy_objects/reset_as_lazy_resets_dynamic_props.phpt @@ -31,7 +31,7 @@ var_dump($obj); var_dump($obj->a); var_dump($obj); -print "# Virtual:\n"; +print "# Proxy:\n"; $obj = new C(); $reflector->resetAsLazyProxy($obj, function ($obj) { @@ -59,7 +59,7 @@ object(C)#%d (2) { object(Canary)#%d (0) { } } -# Virtual: +# Proxy: string(18) "Canary::__destruct" string(18) "Canary::__destruct" lazy proxy object(C)#%d (0) { diff --git a/Zend/tests/lazy_objects/serialize___serialize_may_initialize.phpt b/Zend/tests/lazy_objects/serialize___serialize_may_initialize.phpt index 6d53449e1ec92..632f6e9780880 100644 --- a/Zend/tests/lazy_objects/serialize___serialize_may_initialize.phpt +++ b/Zend/tests/lazy_objects/serialize___serialize_may_initialize.phpt @@ -34,7 +34,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return $c; }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -44,7 +44,7 @@ object(C)#%d (1) { ["a"]=> int(1) } -# Virtual: +# Proxy: string(11) "initializer" string(24) "O:1:"C":1:{s:1:"a";i:1;}" object(C)#%d (1) { diff --git a/Zend/tests/lazy_objects/serialize___serialize_may_not_initialize.phpt b/Zend/tests/lazy_objects/serialize___serialize_may_not_initialize.phpt index e3b5ceadb4e8f..404a35ee10442 100644 --- a/Zend/tests/lazy_objects/serialize___serialize_may_not_initialize.phpt +++ b/Zend/tests/lazy_objects/serialize___serialize_may_not_initialize.phpt @@ -31,7 +31,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -40,7 +40,7 @@ object(C)#%d (0) { ["a"]=> uninitialized(int) } -# Virtual: +# Proxy: string(12) "O:1:"C":0:{}" object(C)#%d (0) { ["a"]=> diff --git a/Zend/tests/lazy_objects/serialize___sleep_initializes.phpt b/Zend/tests/lazy_objects/serialize___sleep_initializes.phpt index 4e183b3b1b148..ec7657afc6916 100644 --- a/Zend/tests/lazy_objects/serialize___sleep_initializes.phpt +++ b/Zend/tests/lazy_objects/serialize___sleep_initializes.phpt @@ -34,7 +34,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return $c; }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -44,7 +44,7 @@ object(C)#%d (1) { ["a"]=> int(1) } -# Virtual: +# Proxy: string(11) "initializer" string(24) "O:1:"C":1:{s:1:"a";i:1;}" object(C)#%d (1) { diff --git a/Zend/tests/lazy_objects/serialize___sleep_skip_flag.phpt b/Zend/tests/lazy_objects/serialize___sleep_skip_flag.phpt index 1b7abd55fe4e1..4641fb2a49ac3 100644 --- a/Zend/tests/lazy_objects/serialize___sleep_skip_flag.phpt +++ b/Zend/tests/lazy_objects/serialize___sleep_skip_flag.phpt @@ -32,7 +32,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { $obj->a = 1; }, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -41,7 +41,7 @@ object(C)#%d (0) { ["a"]=> uninitialized(int) } -# Virtual: +# Proxy: string(12) "O:1:"C":0:{}" object(C)#%d (0) { ["a"]=> diff --git a/Zend/tests/lazy_objects/serialize___sleep_skip_flag_may_initialize.phpt b/Zend/tests/lazy_objects/serialize___sleep_skip_flag_may_initialize.phpt index 51568f2fe0127..ed909a875de47 100644 --- a/Zend/tests/lazy_objects/serialize___sleep_skip_flag_may_initialize.phpt +++ b/Zend/tests/lazy_objects/serialize___sleep_skip_flag_may_initialize.phpt @@ -35,7 +35,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return $c; }, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -46,7 +46,7 @@ object(C)#%d (1) { ["a"]=> int(1) } -# Virtual: +# Proxy: string(11) "initializer" int(1) string(24) "O:1:"C":1:{s:1:"a";i:1;}" diff --git a/Zend/tests/lazy_objects/serialize_hook.phpt b/Zend/tests/lazy_objects/serialize_hook.phpt index dd84899efe316..f2094db2e9a0a 100644 --- a/Zend/tests/lazy_objects/serialize_hook.phpt +++ b/Zend/tests/lazy_objects/serialize_hook.phpt @@ -34,14 +34,14 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECT-- # Ghost: string(11) "initializer" string(14) "C::__construct" string(24) "O:1:"C":1:{s:1:"a";i:1;}" -# Virtual: +# Proxy: string(11) "initializer" string(14) "C::__construct" string(24) "O:1:"C":1:{s:1:"a";i:1;}" diff --git a/Zend/tests/lazy_objects/serialize_initializes.phpt b/Zend/tests/lazy_objects/serialize_initializes.phpt index eea1361c34800..eacb6a985df39 100644 --- a/Zend/tests/lazy_objects/serialize_initializes.phpt +++ b/Zend/tests/lazy_objects/serialize_initializes.phpt @@ -31,14 +31,14 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECT-- # Ghost: string(11) "initializer" string(14) "C::__construct" string(24) "O:1:"C":1:{s:1:"a";i:1;}" -# Virtual: +# Proxy: string(11) "initializer" string(14) "C::__construct" string(24) "O:1:"C":1:{s:1:"a";i:1;}" diff --git a/Zend/tests/lazy_objects/serialize_props_ht.phpt b/Zend/tests/lazy_objects/serialize_props_ht.phpt index ebbdb407e20e7..e8b8834b008de 100644 --- a/Zend/tests/lazy_objects/serialize_props_ht.phpt +++ b/Zend/tests/lazy_objects/serialize_props_ht.phpt @@ -34,14 +34,14 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECT-- # Ghost: string(11) "initializer" string(14) "C::__construct" string(24) "O:1:"C":1:{s:1:"a";i:1;}" -# Virtual: +# Proxy: string(11) "initializer" string(14) "C::__construct" string(24) "O:1:"C":1:{s:1:"a";i:1;}" diff --git a/Zend/tests/lazy_objects/serialize_skip_flag.phpt b/Zend/tests/lazy_objects/serialize_skip_flag.phpt index 5ec4989d864b2..b7f75320fd51c 100644 --- a/Zend/tests/lazy_objects/serialize_skip_flag.phpt +++ b/Zend/tests/lazy_objects/serialize_skip_flag.phpt @@ -31,7 +31,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); }, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -42,7 +42,7 @@ object(C)#%d (1) { ["b"]=> int(1) } -# Virtual: +# Proxy: string(24) "O:1:"C":1:{s:1:"b";i:1;}" object(C)#%d (1) { ["a"]=> diff --git a/Zend/tests/lazy_objects/serialize_skip_flag_props_ht.phpt b/Zend/tests/lazy_objects/serialize_skip_flag_props_ht.phpt index 6292317cd3547..b54f7846eb86d 100644 --- a/Zend/tests/lazy_objects/serialize_skip_flag_props_ht.phpt +++ b/Zend/tests/lazy_objects/serialize_skip_flag_props_ht.phpt @@ -34,7 +34,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); }, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -45,7 +45,7 @@ object(C)#%d (1) { ["b"]=> int(1) } -# Virtual: +# Proxy: string(24) "O:1:"C":1:{s:1:"b";i:1;}" object(C)#%d (1) { ["a"]=> diff --git a/Zend/tests/lazy_objects/skipLazyInitialization.phpt b/Zend/tests/lazy_objects/skipLazyInitialization.phpt index 4f64dfb1eaa50..faff902d0e418 100644 --- a/Zend/tests/lazy_objects/skipLazyInitialization.phpt +++ b/Zend/tests/lazy_objects/skipLazyInitialization.phpt @@ -149,7 +149,7 @@ $factory = function () use ($reflector) { }); }; -test('Virtual', $factory); +test('Proxy', $factory); ?> --EXPECT-- @@ -250,7 +250,7 @@ ReflectionException: setRawValueWithoutLazyInitialization(): ReflectionException: -# Virtual: +# Proxy: ## Property [ private $priv = 'privB' ] diff --git a/Zend/tests/lazy_objects/support_no_internal_classes.phpt b/Zend/tests/lazy_objects/support_no_internal_classes.phpt index b87b096f1882d..f5c8cd1e06738 100644 --- a/Zend/tests/lazy_objects/support_no_internal_classes.phpt +++ b/Zend/tests/lazy_objects/support_no_internal_classes.phpt @@ -16,7 +16,7 @@ try { printf("%s: %s\n", $e::class, $e->getMessage()); } -print "# Virtual:\n"; +print "# Proxy:\n"; try { $obj = $reflector->newLazyProxy(function ($obj) { @@ -30,5 +30,5 @@ try { --EXPECTF-- # Ghost: Error: Cannot make instance of internal class lazy: DateTime is internal -# Virtual: +# Proxy: Error: Cannot make instance of internal class lazy: DateTime is internal diff --git a/Zend/tests/lazy_objects/support_no_internal_sub_classes.phpt b/Zend/tests/lazy_objects/support_no_internal_sub_classes.phpt index 9629f63b20dc8..47a8214626048 100644 --- a/Zend/tests/lazy_objects/support_no_internal_sub_classes.phpt +++ b/Zend/tests/lazy_objects/support_no_internal_sub_classes.phpt @@ -19,7 +19,7 @@ try { printf("%s: %s\n", $e::class, $e->getMessage()); } -print "# Virtual:\n"; +print "# Proxy:\n"; try { $obj = $reflector->newLazyProxy(function ($obj) { @@ -33,5 +33,5 @@ try { --EXPECTF-- # Ghost: Error: Cannot make instance of internal class lazy: C inherits internal class DateTime -# Virtual: +# Proxy: Error: Cannot make instance of internal class lazy: C inherits internal class DateTime diff --git a/Zend/tests/lazy_objects/support_readonly_class.phpt b/Zend/tests/lazy_objects/support_readonly_class.phpt index bb47b0b8af922..cdd420cc121b8 100644 --- a/Zend/tests/lazy_objects/support_readonly_class.phpt +++ b/Zend/tests/lazy_objects/support_readonly_class.phpt @@ -24,7 +24,7 @@ var_dump($obj); var_dump($obj->a); var_dump($obj); -print "# Virtual:\n"; +print "# Proxy:\n"; $obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); @@ -48,7 +48,7 @@ object(C)#%d (1) { ["a"]=> int(1) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["a"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/support_readonly_prop.phpt b/Zend/tests/lazy_objects/support_readonly_prop.phpt index 05d674392da5a..2aabc3a6d18c4 100644 --- a/Zend/tests/lazy_objects/support_readonly_prop.phpt +++ b/Zend/tests/lazy_objects/support_readonly_prop.phpt @@ -24,7 +24,7 @@ var_dump($obj); var_dump($obj->a); var_dump($obj); -print "# Virtual:\n"; +print "# Proxy:\n"; $obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); @@ -48,7 +48,7 @@ object(C)#%d (1) { ["a"]=> int(1) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["a"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/support_stdClass.phpt b/Zend/tests/lazy_objects/support_stdClass.phpt index 2bc61929cdc81..dac4884584133 100644 --- a/Zend/tests/lazy_objects/support_stdClass.phpt +++ b/Zend/tests/lazy_objects/support_stdClass.phpt @@ -13,7 +13,7 @@ $obj = $reflector->newLazyGhost(function ($obj) { }); var_dump($obj); -print "# Virtual:\n"; +print "# Proxy:\n"; $obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); @@ -25,6 +25,6 @@ var_dump($obj); # Ghost: object(stdClass)#%d (0) { } -# Virtual: +# Proxy: object(stdClass)#%d (0) { } diff --git a/Zend/tests/lazy_objects/support_stdClass_sub_classes.phpt b/Zend/tests/lazy_objects/support_stdClass_sub_classes.phpt index 1730dc2fb28ac..bb73b2a54ec0f 100644 --- a/Zend/tests/lazy_objects/support_stdClass_sub_classes.phpt +++ b/Zend/tests/lazy_objects/support_stdClass_sub_classes.phpt @@ -16,7 +16,7 @@ $obj = $reflector->newLazyGhost(function ($obj) { }); var_dump($obj); -print "# Virtual:\n"; +print "# Proxy:\n"; $obj = $reflector->newLazyProxy(function ($obj) { var_dump("initializer"); @@ -28,6 +28,6 @@ var_dump($obj); # Ghost: object(C)#%d (0) { } -# Virtual: +# Proxy: object(C)#%d (0) { } diff --git a/Zend/tests/lazy_objects/unset_defined_no_initialize.phpt b/Zend/tests/lazy_objects/unset_defined_no_initialize.phpt index 164f027c69556..7f09504564d2b 100644 --- a/Zend/tests/lazy_objects/unset_defined_no_initialize.phpt +++ b/Zend/tests/lazy_objects/unset_defined_no_initialize.phpt @@ -37,7 +37,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(1); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -49,7 +49,7 @@ object(C)#%d (0) { ["a"]=> uninitialized(int) } -# Virtual: +# Proxy: object(C)#%d (1) { ["a"]=> int(1) diff --git a/Zend/tests/lazy_objects/unset_hook.phpt b/Zend/tests/lazy_objects/unset_hook.phpt index 2144af5d7c108..e174b22f2cdc4 100644 --- a/Zend/tests/lazy_objects/unset_hook.phpt +++ b/Zend/tests/lazy_objects/unset_hook.phpt @@ -43,7 +43,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(1); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -56,7 +56,7 @@ lazy ghost object(C)#%d (0) { ["b"]=> uninitialized(int) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["b"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/unset_magic_circular_may_initialize.phpt b/Zend/tests/lazy_objects/unset_magic_circular_may_initialize.phpt index 23b40753694a6..0705db85fad9a 100644 --- a/Zend/tests/lazy_objects/unset_magic_circular_may_initialize.phpt +++ b/Zend/tests/lazy_objects/unset_magic_circular_may_initialize.phpt @@ -38,7 +38,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(1); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -52,7 +52,7 @@ object(C)#%d (1) { ["b"]=> int(2) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["b"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/unset_magic_may_initialize.phpt b/Zend/tests/lazy_objects/unset_magic_may_initialize.phpt index 66c2a6f35dba8..4b0cf95763109 100644 --- a/Zend/tests/lazy_objects/unset_magic_may_initialize.phpt +++ b/Zend/tests/lazy_objects/unset_magic_may_initialize.phpt @@ -38,7 +38,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(1); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -53,7 +53,7 @@ object(C)#%d (1) { ["b"]=> int(2) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["b"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/unset_magic_may_not_initialize.phpt b/Zend/tests/lazy_objects/unset_magic_may_not_initialize.phpt index df25ae71f462e..8d22cb4a3cdc9 100644 --- a/Zend/tests/lazy_objects/unset_magic_may_not_initialize.phpt +++ b/Zend/tests/lazy_objects/unset_magic_may_not_initialize.phpt @@ -37,7 +37,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(1); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -49,7 +49,7 @@ lazy ghost object(C)#%d (0) { ["b"]=> uninitialized(int) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["b"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/unset_skipped_no_initialize.phpt b/Zend/tests/lazy_objects/unset_skipped_no_initialize.phpt index 9c61e2406bab7..d990b696c24fc 100644 --- a/Zend/tests/lazy_objects/unset_skipped_no_initialize.phpt +++ b/Zend/tests/lazy_objects/unset_skipped_no_initialize.phpt @@ -44,7 +44,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(1); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: object(C)#%d (2) { @@ -61,7 +61,7 @@ object(C)#%d (0) { ["c"]=> uninitialized(int) } -# Virtual: +# Proxy: object(C)#%d (2) { ["a"]=> NULL diff --git a/Zend/tests/lazy_objects/unset_undefined_dynamic_initializes.phpt b/Zend/tests/lazy_objects/unset_undefined_dynamic_initializes.phpt index 61362aa6c2e3f..792ca9c1cf7b7 100644 --- a/Zend/tests/lazy_objects/unset_undefined_dynamic_initializes.phpt +++ b/Zend/tests/lazy_objects/unset_undefined_dynamic_initializes.phpt @@ -35,7 +35,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(1); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -49,7 +49,7 @@ object(C)#%d (1) { ["b"]=> int(2) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["b"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/unset_undefined_dynamic_initializes_no_props_ht.phpt b/Zend/tests/lazy_objects/unset_undefined_dynamic_initializes_no_props_ht.phpt index 23944286f221f..c27198f3f1968 100644 --- a/Zend/tests/lazy_objects/unset_undefined_dynamic_initializes_no_props_ht.phpt +++ b/Zend/tests/lazy_objects/unset_undefined_dynamic_initializes_no_props_ht.phpt @@ -36,7 +36,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(1); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -47,7 +47,7 @@ object(C)#%d (1) { ["b"]=> int(2) } -# Virtual: +# Proxy: string(12) "before unset" string(11) "initializer" string(14) "C::__construct" diff --git a/Zend/tests/lazy_objects/unset_undefined_initializes.phpt b/Zend/tests/lazy_objects/unset_undefined_initializes.phpt index d582280b57b30..59fc95f902e8f 100644 --- a/Zend/tests/lazy_objects/unset_undefined_initializes.phpt +++ b/Zend/tests/lazy_objects/unset_undefined_initializes.phpt @@ -36,7 +36,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(1); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -50,7 +50,7 @@ object(C)#%d (1) { ["b"]=> int(2) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["b"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/write_dynamic_initializes.phpt b/Zend/tests/lazy_objects/write_dynamic_initializes.phpt index b275d24a9aae5..7864426463456 100644 --- a/Zend/tests/lazy_objects/write_dynamic_initializes.phpt +++ b/Zend/tests/lazy_objects/write_dynamic_initializes.phpt @@ -36,7 +36,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -54,7 +54,7 @@ object(C)#%d (3) { ["custom"]=> int(3) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["b"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/write_initializes.phpt b/Zend/tests/lazy_objects/write_initializes.phpt index bc32d8bfff0c9..2505352308719 100644 --- a/Zend/tests/lazy_objects/write_initializes.phpt +++ b/Zend/tests/lazy_objects/write_initializes.phpt @@ -35,7 +35,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -51,7 +51,7 @@ object(C)#%d (2) { ["b"]=> int(3) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { ["b"]=> uninitialized(int) diff --git a/Zend/tests/lazy_objects/write_magic_circular_may_initialize.phpt b/Zend/tests/lazy_objects/write_magic_circular_may_initialize.phpt index 8fdc882bbe5e1..52a7ae90cbde0 100644 --- a/Zend/tests/lazy_objects/write_magic_circular_may_initialize.phpt +++ b/Zend/tests/lazy_objects/write_magic_circular_may_initialize.phpt @@ -38,7 +38,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -50,7 +50,7 @@ object(C)#%d (1) { ["a"]=> int(3) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { } string(11) "initializer" diff --git a/Zend/tests/lazy_objects/write_magic_may_initialize.phpt b/Zend/tests/lazy_objects/write_magic_may_initialize.phpt index 4804a72fce438..b90bb3cbc57b1 100644 --- a/Zend/tests/lazy_objects/write_magic_may_initialize.phpt +++ b/Zend/tests/lazy_objects/write_magic_may_initialize.phpt @@ -38,7 +38,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -50,7 +50,7 @@ object(C)#%d (1) { ["a"]=> int(3) } -# Virtual: +# Proxy: lazy proxy object(C)#%d (0) { } string(11) "initializer" diff --git a/Zend/tests/lazy_objects/write_skipped_no_initialize.phpt b/Zend/tests/lazy_objects/write_skipped_no_initialize.phpt index e2ee38e9ecb5b..387b1a1cd8fed 100644 --- a/Zend/tests/lazy_objects/write_skipped_no_initialize.phpt +++ b/Zend/tests/lazy_objects/write_skipped_no_initialize.phpt @@ -42,7 +42,7 @@ $obj = $reflector->newLazyProxy(function ($obj) { return new C(); }); -test('Virtual', $obj); +test('Proxy', $obj); --EXPECTF-- # Ghost: @@ -62,7 +62,7 @@ object(C)#%d (3) { ["c"]=> int(2) } -# Virtual: +# Proxy: object(C)#%d (2) { ["a"]=> NULL From 80b422890e27806bf870c04840694e747dc683e4 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Wed, 7 Aug 2024 17:12:47 +0200 Subject: [PATCH 04/56] Fix build --- Zend/zend_object_handlers.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index cceede535cb8d..0a7ba56c5bc6f 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1475,7 +1475,8 @@ ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void if (!zobj) { return; } - return zend_std_unset_property(zobj, name, cache_slot); + zend_std_unset_property(zobj, name, cache_slot); + return; } /* Reset the IS_PROP_UNINIT flag, if it exists and bypass __unset(). */ @@ -1527,7 +1528,8 @@ ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void if (!zobj) { return; } - return zend_std_unset_property(zobj, name, cache_slot); + zend_std_unset_property(zobj, name, cache_slot); + return; } } /* }}} */ From 0832ea2022a62b6d6c8f1e3c737088552ac937f0 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Wed, 7 Aug 2024 17:34:24 +0200 Subject: [PATCH 05/56] Hooks --- .../init_trigger_foreach_hooks.phpt | 96 +++++++++++++++++++ .../init_trigger_json_encode_hooks.phpt | 80 ++++++++++++++++ Zend/zend_object_handlers.h | 7 +- Zend/zend_property_hooks.c | 9 ++ ext/reflection/php_reflection.c | 2 +- 5 files changed, 190 insertions(+), 4 deletions(-) create mode 100644 Zend/tests/lazy_objects/init_trigger_foreach_hooks.phpt create mode 100644 Zend/tests/lazy_objects/init_trigger_json_encode_hooks.phpt diff --git a/Zend/tests/lazy_objects/init_trigger_foreach_hooks.phpt b/Zend/tests/lazy_objects/init_trigger_foreach_hooks.phpt new file mode 100644 index 0000000000000..d955c92c5ab01 --- /dev/null +++ b/Zend/tests/lazy_objects/init_trigger_foreach_hooks.phpt @@ -0,0 +1,96 @@ +--TEST-- +Lazy objects: Foreach initializes object +--FILE-- +b; } + set(int $value) { $this->b = $value; } + } + public int $c { + get { return $this->a + 2; } + } + public function __construct() { + var_dump(__METHOD__); + $this->a = 1; + $this->b = 2; + $this->d = 4; + } +} + +$reflector = new ReflectionClass(C::class); + +print "# Ghost:\n"; + +$obj = $reflector->newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +foreach ($obj as $prop => $value) { + var_dump($prop, $value); +} + +print "# Proxy:\n"; + +$obj = $reflector->newLazyProxy(function ($obj) { + var_dump("initializer"); + return new C(); +}); + +foreach ($obj as $prop => $value) { + var_dump($prop, $value); +} + +print "# Ghost (init exception):\n"; + +$obj = $reflector->newLazyGhost(function ($obj) { + throw new \Exception(); +}); + +try { + var_dump(json_encode($obj)); +} catch (\Exception $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +print "# Proxy (init exception):\n"; + +$obj = $reflector->newLazyProxy(function ($obj) { + throw new \Exception(); +}); + +try { + var_dump(json_encode($obj)); +} catch (\Exception $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +--EXPECT-- +# Ghost: +string(11) "initializer" +string(14) "C::__construct" +string(1) "a" +int(1) +string(1) "b" +int(2) +string(1) "c" +int(3) +string(1) "d" +int(4) +# Proxy: +string(11) "initializer" +string(14) "C::__construct" +string(1) "a" +int(1) +string(1) "b" +int(2) +string(1) "c" +int(3) +# Ghost (init exception): +Exception: +# Proxy (init exception): +Exception: diff --git a/Zend/tests/lazy_objects/init_trigger_json_encode_hooks.phpt b/Zend/tests/lazy_objects/init_trigger_json_encode_hooks.phpt new file mode 100644 index 0000000000000..c754d030e4305 --- /dev/null +++ b/Zend/tests/lazy_objects/init_trigger_json_encode_hooks.phpt @@ -0,0 +1,80 @@ +--TEST-- +Lazy objects: json_encode initializes object +--FILE-- +b; } + set(int $value) { $this->b = $value; } + } + public int $c { + get { return $this->a + 2; } + } + public function __construct() { + var_dump(__METHOD__); + $this->a = 1; + $this->b = 2; + $this->d = 4; + } +} + +$reflector = new ReflectionClass(C::class); + +print "# Ghost:\n"; + +$obj = $reflector->newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +var_dump(json_encode($obj)); + +print "# Proxy:\n"; + +$obj = $reflector->newLazyProxy(function ($obj) { + var_dump("initializer"); + return new C(); +}); + +var_dump(json_encode($obj)); + +print "# Ghost (init exception):\n"; + +$obj = $reflector->newLazyGhost(function ($obj) { + throw new \Exception(); +}); + +try { + var_dump(json_encode($obj)); +} catch (\Exception $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +print "# Proxy (init exception):\n"; + +$obj = $reflector->newLazyProxy(function ($obj) { + throw new \Exception(); +}); + +try { + var_dump(json_encode($obj)); +} catch (\Exception $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +--EXPECT-- +# Ghost: +string(11) "initializer" +string(14) "C::__construct" +string(25) "{"a":1,"b":2,"c":3,"d":4}" +# Proxy: +string(11) "initializer" +string(14) "C::__construct" +string(25) "{"a":1,"b":2,"c":3,"d":4}" +# Ghost (init exception): +Exception: +# Proxy (init exception): +Exception: diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index 7ac2051ea3870..c84f13f4411a7 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -22,6 +22,7 @@ #include +#include "zend_hash.h" #include "zend_types.h" #include "zend_property_hooks.h" #include "zend_lazy_objects.h" @@ -275,9 +276,9 @@ ZEND_API HashTable *rebuild_object_properties_internal(zend_object *zobj); static zend_always_inline HashTable *zend_std_get_properties_ex(zend_object *object) { if (UNEXPECTED(zend_lazy_object_must_init(object))) { - zend_object *instance = zend_lazy_object_init(object); - if (EXPECTED(instance)) { - object = instance; + object = zend_lazy_object_init(object); + if (UNEXPECTED(!object)) { + return object->properties = (zend_array*) &zend_empty_array; } } if (!object->properties) { diff --git a/Zend/zend_property_hooks.c b/Zend/zend_property_hooks.c index b00a526125c27..9cfa15ecafa4d 100644 --- a/Zend/zend_property_hooks.c +++ b/Zend/zend_property_hooks.c @@ -18,6 +18,8 @@ #include "zend.h" #include "zend_API.h" +#include "zend_hash.h" +#include "zend_lazy_objects.h" #include "zend_property_hooks.h" typedef struct { @@ -49,6 +51,13 @@ static uint32_t zho_num_backed_props(zend_object *zobj) static zend_array *zho_build_properties_ex(zend_object *zobj, bool check_access, bool include_dynamic_props) { + if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { + zobj = zend_lazy_object_init(zobj); + if (UNEXPECTED(!zobj)) { + return (zend_array*) &zend_empty_array; + } + } + zend_class_entry *ce = zobj->ce; zend_array *properties = zend_new_array(ce->default_properties_count); zend_hash_real_init_mixed(properties); diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 9354bf626877e..5114df206913f 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -5327,7 +5327,7 @@ ZEND_METHOD(ReflectionClass, initializeLazyObject) if (zend_lazy_object_initialized(object)) { RETURN_OBJ_COPY(zend_lazy_object_get_instance(object)); } else { - ZEND_ASSERT(EG(exception)); + RETURN_THROWS(); } } /* }}} */ From 0b2f63246be31967ca4ff21b79bbca2d19c55618 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Sat, 10 Aug 2024 17:38:36 +0200 Subject: [PATCH 06/56] Fix windows build --- win32/build/config.w32 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/win32/build/config.w32 b/win32/build/config.w32 index 668995045725b..08edb81d11947 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -240,7 +240,8 @@ ADD_SOURCES("Zend", "zend_language_parser.c zend_language_scanner.c \ zend_default_classes.c zend_execute.c zend_strtod.c zend_gc.c zend_closures.c zend_weakrefs.c \ zend_float.c zend_string.c zend_generators.c zend_virtual_cwd.c zend_ast.c \ zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_observer.c zend_system_id.c \ - zend_enum.c zend_fibers.c zend_atomic.c zend_hrtime.c zend_frameless_function.c zend_property_hooks.c"); + zend_enum.c zend_fibers.c zend_atomic.c zend_hrtime.c zend_frameless_function.c zend_property_hooks.c \ + zend_lazy_objects.c"); ADD_SOURCES("Zend\\Optimizer", "zend_optimizer.c pass1.c pass3.c optimize_func_calls.c block_pass.c optimize_temp_vars_5.c nop_removal.c compact_literals.c zend_cfg.c zend_dfg.c dfa_pass.c zend_ssa.c zend_inference.c zend_func_info.c zend_call_graph.c zend_dump.c escape_analysis.c compact_vars.c dce.c sccp.c scdf.c"); var PHP_ASSEMBLER = PATH_PROG({ From 6460680834efc62601759630b25780163d02d811 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 13 Aug 2024 12:47:28 +0200 Subject: [PATCH 07/56] Fix test --- Zend/tests/lazy_objects/unclean_shutdown.phpt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Zend/tests/lazy_objects/unclean_shutdown.phpt b/Zend/tests/lazy_objects/unclean_shutdown.phpt index d162ae2973678..9ec02b5a7c4d7 100644 --- a/Zend/tests/lazy_objects/unclean_shutdown.phpt +++ b/Zend/tests/lazy_objects/unclean_shutdown.phpt @@ -10,9 +10,10 @@ class C { $reflector = new ReflectionClass(C::class); $obj = $reflector->newLazyGhost(function ($obj) { - trigger_error('Fatal', E_USER_ERROR); + // Trigger a fatal error to get an unclean shutdown + class bool {} }); var_dump($obj->a); --EXPECTF-- -Fatal error: Fatal in %s on line %d +Fatal error: Cannot use 'bool' as class name%s on line %d From a674d55a61baa6aa1532c70ea581343cbde1efc5 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 13 Aug 2024 14:00:10 +0200 Subject: [PATCH 08/56] JIT --- .../lazy_objects/jit_assign_obj_dynamic.phpt | 69 ++++++++++++++++++ .../jit_assign_obj_op_dynamic.phpt | 70 +++++++++++++++++++ .../jit_assign_obj_op_prop_info.phpt | 69 ++++++++++++++++++ .../jit_assign_obj_op_unknown_prop_info.phpt | 47 +++++++++++++ ...sign_obj_op_unknown_prop_info_untyped.phpt | 48 +++++++++++++ .../jit_assign_obj_prop_info.phpt | 69 ++++++++++++++++++ .../jit_assign_obj_unknown_prop_info.phpt | 46 ++++++++++++ ..._assign_obj_unknown_prop_info_untyped.phpt | 47 +++++++++++++ ext/opcache/jit/zend_jit_ir.c | 26 ++++--- 9 files changed, 477 insertions(+), 14 deletions(-) create mode 100644 Zend/tests/lazy_objects/jit_assign_obj_dynamic.phpt create mode 100644 Zend/tests/lazy_objects/jit_assign_obj_op_dynamic.phpt create mode 100644 Zend/tests/lazy_objects/jit_assign_obj_op_prop_info.phpt create mode 100644 Zend/tests/lazy_objects/jit_assign_obj_op_unknown_prop_info.phpt create mode 100644 Zend/tests/lazy_objects/jit_assign_obj_op_unknown_prop_info_untyped.phpt create mode 100644 Zend/tests/lazy_objects/jit_assign_obj_prop_info.phpt create mode 100644 Zend/tests/lazy_objects/jit_assign_obj_unknown_prop_info.phpt create mode 100644 Zend/tests/lazy_objects/jit_assign_obj_unknown_prop_info_untyped.phpt diff --git a/Zend/tests/lazy_objects/jit_assign_obj_dynamic.phpt b/Zend/tests/lazy_objects/jit_assign_obj_dynamic.phpt new file mode 100644 index 0000000000000..d49fb585cecc9 --- /dev/null +++ b/Zend/tests/lazy_objects/jit_assign_obj_dynamic.phpt @@ -0,0 +1,69 @@ +--TEST-- +Lazy objects: JIT: ASSIGN_OBJ with dynamic prop +--FILE-- +b = 3; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + $obj->a = 2; + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Proxy', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +object(C)#%d (2) { + ["b"]=> + int(3) + ["a"]=> + int(2) +} +# Proxy: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["b"]=> + int(3) + ["a"]=> + int(2) + } +} diff --git a/Zend/tests/lazy_objects/jit_assign_obj_op_dynamic.phpt b/Zend/tests/lazy_objects/jit_assign_obj_op_dynamic.phpt new file mode 100644 index 0000000000000..cdf639815e3bb --- /dev/null +++ b/Zend/tests/lazy_objects/jit_assign_obj_op_dynamic.phpt @@ -0,0 +1,70 @@ +--TEST-- +Lazy objects: JIT: ASSIGN_OBJ_OP with dynamic prop +--FILE-- +a = 1; + $this->b = 3; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + $obj->a += 1; + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Proxy', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +object(C)#%d (2) { + ["b"]=> + int(1) + ["a"]=> + int(2) +} +# Proxy: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["b"]=> + int(3) + ["a"]=> + int(2) + } +} diff --git a/Zend/tests/lazy_objects/jit_assign_obj_op_prop_info.phpt b/Zend/tests/lazy_objects/jit_assign_obj_op_prop_info.phpt new file mode 100644 index 0000000000000..31689723c202c --- /dev/null +++ b/Zend/tests/lazy_objects/jit_assign_obj_op_prop_info.phpt @@ -0,0 +1,69 @@ +--TEST-- +Lazy objects: JIT: ASSIGN_OBJ_OP with known prop_info +--FILE-- +b = 3; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + $obj->a += 1; + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Proxy', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + int(3) +} +# Proxy: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + int(3) + } +} diff --git a/Zend/tests/lazy_objects/jit_assign_obj_op_unknown_prop_info.phpt b/Zend/tests/lazy_objects/jit_assign_obj_op_unknown_prop_info.phpt new file mode 100644 index 0000000000000..7c812514eb2e9 --- /dev/null +++ b/Zend/tests/lazy_objects/jit_assign_obj_op_unknown_prop_info.phpt @@ -0,0 +1,47 @@ +--TEST-- +Lazy objects: JIT: ASSIGN_OBJ_OP with unknown prop info +--FILE-- +a = 1; + $this->b = 2; + } + function test(object $obj) { + $obj->a += 1; + } +} + +$reflector = new ReflectionClass(C::class); + +for ($i = 0; $i < 2; $i++) { + $obj = $reflector->newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->__construct(); + }); + // Call via reflection to avoid inlining. + // - test() handlers are executed once, and prime the runtime cache + // - On subsequent calls, the JIT'ed code is used, and we enter the valid runtime cache path + $reflector->getMethod('test')->invoke($obj, $obj); + var_dump($obj); +} + +--EXPECTF-- +string(11) "initializer" +object(C)#%d (2) { + ["a":"C":private]=> + int(2) + ["b"]=> + int(2) +} +string(11) "initializer" +object(C)#%d (2) { + ["a":"C":private]=> + int(2) + ["b"]=> + int(2) +} diff --git a/Zend/tests/lazy_objects/jit_assign_obj_op_unknown_prop_info_untyped.phpt b/Zend/tests/lazy_objects/jit_assign_obj_op_unknown_prop_info_untyped.phpt new file mode 100644 index 0000000000000..211090110245a --- /dev/null +++ b/Zend/tests/lazy_objects/jit_assign_obj_op_unknown_prop_info_untyped.phpt @@ -0,0 +1,48 @@ +--TEST-- +Lazy objects: JIT: ASSIGN_OBJ_OP with unknown prop info untyped +--FILE-- +a = 1; + $this->b = 2; + } + function test(object $obj) { + $obj->a += 1; + } +} + +$reflector = new ReflectionClass(C::class); + +for ($i = 0; $i < 2; $i++) { + $obj = $reflector->newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->__construct(); + }); + // Call via reflection to avoid inlining. + // - test() handlers are executed once, and prime the runtime cache + // - On subsequent calls, the JIT'ed code is used, and we enter the valid runtime cache path + $reflector->getMethod('test')->invoke($obj, $obj); + var_dump($obj); +} + +?> +--EXPECTF-- +string(11) "initializer" +object(C)#%d (2) { + ["a":"C":private]=> + int(2) + ["b"]=> + int(2) +} +string(11) "initializer" +object(C)#%d (2) { + ["a":"C":private]=> + int(2) + ["b"]=> + int(2) +} diff --git a/Zend/tests/lazy_objects/jit_assign_obj_prop_info.phpt b/Zend/tests/lazy_objects/jit_assign_obj_prop_info.phpt new file mode 100644 index 0000000000000..631ba647e8859 --- /dev/null +++ b/Zend/tests/lazy_objects/jit_assign_obj_prop_info.phpt @@ -0,0 +1,69 @@ +--TEST-- +Lazy objects: JIT: ASSIGN_OBJ with known prop_info +--FILE-- +b = 3; + } +} + +function test(string $name, object $obj) { + printf("# %s:\n", $name); + + var_dump($obj); + $obj->a = 2; + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); + +$obj = $reflector->newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function ($obj) { + var_dump("initializer"); + return new C(); +}); + +test('Proxy', $obj); + +--EXPECTF-- +# Ghost: +lazy ghost object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +object(C)#%d (2) { + ["a"]=> + int(2) + ["b"]=> + int(3) +} +# Proxy: +lazy proxy object(C)#%d (0) { + ["b"]=> + uninitialized(int) +} +string(11) "initializer" +string(14) "C::__construct" +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["a"]=> + int(2) + ["b"]=> + int(3) + } +} diff --git a/Zend/tests/lazy_objects/jit_assign_obj_unknown_prop_info.phpt b/Zend/tests/lazy_objects/jit_assign_obj_unknown_prop_info.phpt new file mode 100644 index 0000000000000..6d48cbd2861c1 --- /dev/null +++ b/Zend/tests/lazy_objects/jit_assign_obj_unknown_prop_info.phpt @@ -0,0 +1,46 @@ +--TEST-- +Lazy objects: JIT: ASSIGN_OBJ with unknown prop info +--FILE-- +b = 2; + } + function test(object $obj) { + $obj->a = 1; + } +} + +$reflector = new ReflectionClass(C::class); + +for ($i = 0; $i < 2; $i++) { + $obj = $reflector->newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->__construct(); + }); + // Call via reflection to avoid inlining. + // - test() handlers are executed once, and prime the runtime cache + // - On subsequent calls, the JIT'ed code is used, and we enter the valid runtime cache path + $reflector->getMethod('test')->invoke($obj, $obj); + var_dump($obj); +} + +--EXPECTF-- +string(11) "initializer" +object(C)#%d (2) { + ["a":"C":private]=> + int(1) + ["b"]=> + int(2) +} +string(11) "initializer" +object(C)#%d (2) { + ["a":"C":private]=> + int(1) + ["b"]=> + int(2) +} diff --git a/Zend/tests/lazy_objects/jit_assign_obj_unknown_prop_info_untyped.phpt b/Zend/tests/lazy_objects/jit_assign_obj_unknown_prop_info_untyped.phpt new file mode 100644 index 0000000000000..f3c2d7dbe722a --- /dev/null +++ b/Zend/tests/lazy_objects/jit_assign_obj_unknown_prop_info_untyped.phpt @@ -0,0 +1,47 @@ +--TEST-- +Lazy objects: JIT: ASSIGN_OBJ with unknown prop info untyped +--FILE-- +b = 2; + } + function test(object $obj) { + $obj->a = 1; + } +} + +$reflector = new ReflectionClass(C::class); + +for ($i = 0; $i < 2; $i++) { + $obj = $reflector->newLazyGhost(function ($obj) { + var_dump("initializer"); + $obj->__construct(); + }); + // Call via reflection to avoid inlining. + // - test() handlers are executed once, and prime the runtime cache + // - On subsequent calls, the JIT'ed code is used, and we enter the valid runtime cache path + $reflector->getMethod('test')->invoke($obj, $obj); + var_dump($obj); +} + +?> +--EXPECTF-- +string(11) "initializer" +object(C)#%d (2) { + ["a":"C":private]=> + int(1) + ["b"]=> + int(2) +} +string(11) "initializer" +object(C)#%d (2) { + ["a":"C":private]=> + int(1) + ["b"]=> + int(2) +} diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 49ddf40a0e7ce..9b1bf9a71dde1 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -14466,22 +14466,20 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, ZEND_ASSERT(slow_inputs == IR_UNUSED); goto slow_path; } - if (!ce || ce_is_instanceof || !(ce->ce_flags & ZEND_ACC_IMMUTABLE) || ce->__get || ce->__set) { - // Undefined property with magic __get()/__set() - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); + // Undefined property with potential magic __get()/__set() or lazy object + if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { + int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); + const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr)); - } else { - ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr)); - ir_IF_FALSE_cold(if_def); - ir_END_list(slow_inputs); - ir_IF_TRUE(if_def); + if (!exit_addr) { + return 0; } + ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr)); + } else { + ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr)); + ir_IF_FALSE_cold(if_def); + ir_END_list(slow_inputs); + ir_IF_TRUE(if_def); } if (ZEND_TYPE_IS_SET(prop_info->type)) { ir_ref ref, arg3, arg4; From 627de1f0afa5bc3f5f2a47e297e18a3129a61aa0 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 13 Aug 2024 14:20:01 +0200 Subject: [PATCH 09/56] Remove TODO --- Zend/zend_lazy_objects.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 3e2740a08ed07..91ccad3af5655 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -469,7 +469,6 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj) /* unset() properties of the proxy. This ensures that all accesses are be * delegated to the backing instance from now on. */ - // TODO: test that props are undef after initialization zend_object_dtor_dynamic_properties(obj); obj->properties = NULL; From a7249389664e8a83c1c4abc4d2c042318dc62b9d Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 13 Aug 2024 14:20:28 +0200 Subject: [PATCH 10/56] Expose initializer zv to gc --- Zend/zend_lazy_objects.c | 37 +++++++++++++++++++++++++++++++++++++ Zend/zend_lazy_objects.h | 1 + Zend/zend_object_handlers.c | 30 +----------------------------- 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 91ccad3af5655..eee168b0afd70 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -39,6 +39,7 @@ #include "zend_API.h" #include "zend_compile.h" #include "zend_execute.h" +#include "zend_gc.h" #include "zend_hash.h" #include "zend_object_handlers.h" #include "zend_objects_API.h" @@ -665,3 +666,39 @@ HashTable *zend_lazy_object_debug_info(zend_object *object, int *is_temp) *is_temp = 0; return zend_get_properties_no_init(object); } + +HashTable *zend_lazy_object_get_gc(zend_object *zobj, zval **table, int *n) +{ + ZEND_ASSERT(zend_object_is_lazy(zobj)); + + zend_lazy_object_info *info = zend_lazy_object_get_info(zobj); + zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create(); + + if (zend_lazy_object_initialized(zobj)) { + ZEND_ASSERT(zend_object_is_lazy_proxy(zobj)); + zend_get_gc_buffer_add_obj(gc_buffer, info->u.instance); + zend_get_gc_buffer_use(gc_buffer, table, n); + /* Initialized proxy object can not have properties */ + return NULL; + } + + zend_fcall_info_cache *fcc = &info->u.initializer.fcc; + if (fcc->object) { + zend_get_gc_buffer_add_obj(gc_buffer, fcc->object); + } + if (fcc->closure) { + zend_get_gc_buffer_add_obj(gc_buffer, fcc->closure); + } + zend_get_gc_buffer_add_zval(gc_buffer, &info->u.initializer.zv); + + /* Uninitialized lazy objects can not have dynamic properties, so we can + * ignore zobj->properties. */ + zval *prop = zobj->properties_table; + zval *end = prop + zobj->ce->default_properties_count; + for ( ; prop < end; prop++) { + zend_get_gc_buffer_add_zval(gc_buffer, prop); + } + + zend_get_gc_buffer_use(gc_buffer, table, n); + return NULL; +} diff --git a/Zend/zend_lazy_objects.h b/Zend/zend_lazy_objects.h index ca1ad4a630a3d..87654b1396095 100644 --- a/Zend/zend_lazy_objects.h +++ b/Zend/zend_lazy_objects.h @@ -74,6 +74,7 @@ zend_lazy_object_flags_t zend_lazy_object_get_flags(zend_object *obj); void zend_lazy_object_del_info(zend_object *obj); zend_object *zend_lazy_object_clone(zend_object *old_obj); HashTable *zend_lazy_object_debug_info(zend_object *object, int *is_temp); +HashTable *zend_lazy_object_get_gc(zend_object *zobj, zval **table, int *n); bool zend_lazy_object_decr_lazy_props(zend_object *obj); void zend_lazy_object_realize(zend_object *obj); diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 0a7ba56c5bc6f..97793bf597a8b 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -164,35 +164,7 @@ ZEND_API HashTable *zend_std_get_gc(zend_object *zobj, zval **table, int *n) /* return zobj->handlers->get_properties(zobj); } else { if (UNEXPECTED(zend_object_is_lazy(zobj))) { - zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create(); - if (zend_lazy_object_initialized(zobj)) { - ZEND_ASSERT(zend_object_is_lazy_proxy(zobj)); - zend_object *instance = zend_lazy_object_get_instance(zobj); - zend_get_gc_buffer_add_obj(gc_buffer, instance); - } else { - zend_fcall_info_cache* initializer = zend_lazy_object_get_initializer_fcc(zobj); - if (initializer) { - // TODO: also expose _get_initializer_zv() to the GC - if (initializer->object) { - zend_get_gc_buffer_add_obj(gc_buffer, initializer->object); - } - if (initializer->closure) { - zend_get_gc_buffer_add_obj(gc_buffer, initializer->closure); - } - } - } - if (zobj->properties) { - zend_get_gc_buffer_use(gc_buffer, table, n); - return zobj->properties; - } else { - zval *prop = zobj->properties_table; - zval *end = prop + zobj->ce->default_properties_count; - for ( ; prop < end; prop++) { - zend_get_gc_buffer_add_zval(gc_buffer, prop); - } - zend_get_gc_buffer_use(gc_buffer, table, n); - return NULL; - } + return zend_lazy_object_get_gc(zobj, table, n); } else if (zobj->properties) { *table = NULL; *n = 0; From ac439e8b2bd1b57782f9c55ce88ed520bd547812 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 13 Aug 2024 14:21:07 +0200 Subject: [PATCH 11/56] Add test --- .../reset_as_lazy_accepts_sub_classes.phpt | 28 +++++++++++++++++++ ext/reflection/php_reflection.c | 1 - 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/lazy_objects/reset_as_lazy_accepts_sub_classes.phpt diff --git a/Zend/tests/lazy_objects/reset_as_lazy_accepts_sub_classes.phpt b/Zend/tests/lazy_objects/reset_as_lazy_accepts_sub_classes.phpt new file mode 100644 index 0000000000000..b836fbfea58d7 --- /dev/null +++ b/Zend/tests/lazy_objects/reset_as_lazy_accepts_sub_classes.phpt @@ -0,0 +1,28 @@ +--TEST-- +Lazy objects: resetAsLazy*() accept a sub-class of the reflected class +--FILE-- +resetAsLazyGhost(new A(), function () {}); +$reflector->resetAsLazyGhost(new B(), function () {}); + +try { + $reflector->resetAsLazyGhost(new C(), function () {}); +} catch (TypeError $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +?> +==DONE== +--EXPECT-- +TypeError: ReflectionClass::resetAsLazyGhost(): Argument #1 ($object) must be of type A, C given +==DONE== diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 5114df206913f..70c3f4f198369 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -5208,7 +5208,6 @@ void reflection_class_new_lazy(INTERNAL_FUNCTION_PARAMETERS, if (is_reset) { ZEND_PARSE_PARAMETERS_START(2, 3) - // TODO: check that obj->ce matches ce Z_PARAM_OBJ_OF_CLASS(obj, ce) Z_PARAM_FUNC(fci, fcc) Z_PARAM_OPTIONAL From bd03b05548db63cc5dd2cf473cb50efb7e1da93b Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 13 Aug 2024 14:21:37 +0200 Subject: [PATCH 12/56] Internal param name consistency with api --- ext/reflection/php_reflection.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 70c3f4f198369..5cf1d936faeed 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -5199,7 +5199,7 @@ void reflection_class_new_lazy(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce; zend_fcall_info fci; zend_fcall_info_cache fcc; - zend_long flags = 0; + zend_long options = 0; ZEND_ASSERT(strategy == ZEND_LAZY_OBJECT_STRATEGY_GHOST || strategy == ZEND_LAZY_OBJECT_STRATEGY_PROXY); @@ -5211,20 +5211,19 @@ void reflection_class_new_lazy(INTERNAL_FUNCTION_PARAMETERS, Z_PARAM_OBJ_OF_CLASS(obj, ce) Z_PARAM_FUNC(fci, fcc) Z_PARAM_OPTIONAL - // TODO: check named param - Z_PARAM_LONG(flags) + Z_PARAM_LONG(options) ZEND_PARSE_PARAMETERS_END(); } else { ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_FUNC(fci, fcc) Z_PARAM_OPTIONAL - Z_PARAM_LONG(flags) + Z_PARAM_LONG(options) ZEND_PARSE_PARAMETERS_END(); obj = NULL; } - if (flags & ~ZEND_LAZY_OBJECT_USER_FLAGS) { - zend_throw_exception_ex(reflection_exception_ptr, 0, "Invalid flags"); + if (options & ~ZEND_LAZY_OBJECT_USER_FLAGS) { + zend_throw_exception_ex(reflection_exception_ptr, 0, "Invalid options"); RETURN_THROWS(); } @@ -5245,7 +5244,7 @@ void reflection_class_new_lazy(INTERNAL_FUNCTION_PARAMETERS, } obj = zend_object_make_lazy(obj, ce, &fci.function_name, &fcc, - strategy | flags); + strategy | options); if (!obj) { RETURN_THROWS(); From ed7d39ca8368097d167b3aaa2b462609ac16b8b5 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Fri, 16 Aug 2024 16:03:11 +0200 Subject: [PATCH 13/56] Update comment --- Zend/zend_lazy_objects.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index eee168b0afd70..4a35d35fedbae 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -22,7 +22,8 @@ * This is implemented by using the same fallback mechanism as __get and __set * magic methods that is triggered when an undefined property is accessed. * - * Execution of methods or virtual property hooks do not trigger initialization. + * Execution of methods or virtual property hooks do not trigger initialization + * until they access properties. * * A lazy object can be created via the Reflection API. The user specifies an * initializer function that is called when initialization is required. From 56d10dbb1088de5394652a308cba0fab294dabbf Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Fri, 16 Aug 2024 16:03:23 +0200 Subject: [PATCH 14/56] Add assertion --- Zend/zend_object_handlers.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 97793bf597a8b..f26fd4311b571 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -153,6 +153,8 @@ ZEND_API HashTable *zend_get_properties_no_init(zend_object *zobj) return zobj->properties; } + ZEND_ASSERT(!zend_object_is_lazy(zobj)); + return zobj->handlers->get_properties(zobj); } From a509e91ee21e33abfc22b03122e8cfa72586c16e Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Fri, 16 Aug 2024 16:03:37 +0200 Subject: [PATCH 15/56] Cleanup --- Zend/zend_object_handlers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index f26fd4311b571..4ce9e21ca7c06 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1168,7 +1168,7 @@ found:; } Z_TRY_ADDREF_P(value); - variable_ptr = zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + variable_ptr = zend_hash_add_new(zend_std_get_properties(zobj), name, value); } } From e8d1b9da1a2bc6c2ed72710b2e25d4dbde24f847 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 16:27:22 +0200 Subject: [PATCH 16/56] Rename zend_object.flags --- Zend/zend_objects.c | 2 +- Zend/zend_types.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index bdfc2a814aa35..3c824702e95f8 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -32,7 +32,7 @@ static zend_always_inline void _zend_object_std_init(zend_object *object, zend_c GC_SET_REFCOUNT(object, 1); GC_TYPE_INFO(object) = GC_OBJECT; object->ce = ce; - object->flags = 0; + object->extra_flags = 0; object->handlers = ce->default_object_handlers; object->properties = NULL; zend_objects_store_put(object); diff --git a/Zend/zend_types.h b/Zend/zend_types.h index d6aec3a35b4bd..00c4b652988a5 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -556,7 +556,7 @@ typedef struct _HashTableIterator { struct _zend_object { zend_refcounted_h gc; uint32_t handle; // TODO: may be removed ??? - uint32_t flags; + uint32_t extra_flags; /* OBJ_EXTRA_FLAGS() */ zend_class_entry *ce; const zend_object_handlers *handlers; HashTable *properties; @@ -835,7 +835,7 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) { #define IS_OBJ_LAZY (1U<<31) /* Virtual proxy or uninitialized Ghost */ #define IS_OBJ_LAZY_PROXY (1U<<30) /* Virtual proxy (may be initialized) */ -#define OBJ_EXTRA_FLAGS(obj) ((obj)->flags) +#define OBJ_EXTRA_FLAGS(obj) ((obj)->extra_flags) /* Fast class cache */ #define ZSTR_HAS_CE_CACHE(s) (GC_FLAGS(s) & IS_STR_CLASS_NAME_MAP_PTR) From d7bf62401ef51ceea0488be25f5487acb8b75e59 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 16:28:36 +0200 Subject: [PATCH 17/56] Rename zend_get_properties_no_init --- Zend/zend_builtin_functions.c | 2 +- Zend/zend_lazy_objects.c | 2 +- Zend/zend_object_handlers.c | 8 ++++---- Zend/zend_object_handlers.h | 2 +- ext/reflection/php_reflection.c | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 9b797880684f1..654ba7e7ea129 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -885,7 +885,7 @@ ZEND_FUNCTION(get_mangled_object_vars) Z_PARAM_OBJ(obj) ZEND_PARSE_PARAMETERS_END(); - properties = zend_get_properties_no_init(obj); + properties = zend_get_properties_no_lazy_init(obj); if (!properties) { ZVAL_EMPTY_ARRAY(return_value); return; diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 4a35d35fedbae..84e26faccb418 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -665,7 +665,7 @@ HashTable *zend_lazy_object_debug_info(zend_object *object, int *is_temp) } *is_temp = 0; - return zend_get_properties_no_init(object); + return zend_get_properties_no_lazy_init(object); } HashTable *zend_lazy_object_get_gc(zend_object *zobj, zval **table, int *n) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 4ce9e21ca7c06..345772fc2083a 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -138,13 +138,13 @@ ZEND_API HashTable *zend_std_get_properties(zend_object *zobj) /* {{{ */ /* }}} */ /* Fetch properties HashTable without triggering lazy initialization */ -ZEND_API HashTable *zend_get_properties_no_init(zend_object *zobj) +ZEND_API HashTable *zend_get_properties_no_lazy_init(zend_object *zobj) { if (zobj->handlers->get_properties == zend_std_get_properties) { if (UNEXPECTED(zend_object_is_lazy_proxy(zobj) && zend_lazy_object_initialized(zobj))) { zend_object *instance = zend_lazy_object_get_instance(zobj); - return zend_get_properties_no_init(instance); + return zend_get_properties_no_lazy_init(instance); } if (!zobj->properties) { @@ -2379,7 +2379,7 @@ ZEND_API HashTable *zend_std_get_properties_for(zend_object *obj, zend_prop_purp } return ht; case ZEND_PROP_PURPOSE_ARRAY_CAST: - ht = zend_get_properties_no_init(obj); + ht = zend_get_properties_no_lazy_init(obj); if (ht) { GC_TRY_ADDREF(ht); } @@ -2387,7 +2387,7 @@ ZEND_API HashTable *zend_std_get_properties_for(zend_object *obj, zend_prop_purp case ZEND_PROP_PURPOSE_SERIALIZE: { if (zend_object_is_lazy(obj) && !zend_lazy_object_initialize_on_serialize(obj)) { - ht = zend_get_properties_no_init(obj); + ht = zend_get_properties_no_lazy_init(obj); } else { ht = obj->handlers->get_properties(obj); } diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index c84f13f4411a7..e392aefbfd5cb 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -253,7 +253,7 @@ ZEND_API ZEND_COLD bool zend_std_unset_static_property(zend_class_entry *ce, zen ZEND_API zend_function *zend_std_get_constructor(zend_object *object); ZEND_API struct _zend_property_info *zend_get_property_info(const zend_class_entry *ce, zend_string *member, int silent); ZEND_API HashTable *zend_std_get_properties(zend_object *object); -ZEND_API HashTable *zend_get_properties_no_init(zend_object *zobj); +ZEND_API HashTable *zend_get_properties_no_lazy_init(zend_object *zobj); ZEND_API HashTable *zend_std_get_gc(zend_object *object, zval **table, int *n); ZEND_API HashTable *zend_std_get_debug_info(zend_object *object, int *is_temp); ZEND_API zend_result zend_std_cast_object_tostring(zend_object *object, zval *writeobj, int type); diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 5cf1d936faeed..a45c78d64e85d 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -478,7 +478,7 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char smart_str_append_printf(str, "%s }\n", indent); if (obj && Z_TYPE_P(obj) == IS_OBJECT) { - HashTable *properties = zend_get_properties_no_init(Z_OBJ_P(obj)); + HashTable *properties = zend_get_properties_no_lazy_init(Z_OBJ_P(obj)); zend_string *prop_name; smart_str prop_str = {0}; From f70412c281ca57f67b031c312798f1d90465e535 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 16:33:11 +0200 Subject: [PATCH 18/56] De-dup --- ext/standard/var.c | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/ext/standard/var.c b/ext/standard/var.c index 479412de4aea2..8db4b2d755445 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -88,6 +88,18 @@ static void php_object_property_dump(zend_property_info *prop_info, zval *zv, ze } /* }}} */ +static const char *php_var_dump_object_prefix(zend_object *obj) { + if (EXPECTED(!zend_object_is_lazy(obj))) { + return ""; + } + + if (zend_object_is_lazy_proxy(obj)) { + return "lazy proxy "; + } + + return "lazy ghost "; +} + PHPAPI void php_var_dump(zval *struc, int level) /* {{{ */ { HashTable *myht; @@ -165,17 +177,7 @@ PHPAPI void php_var_dump(zval *struc, int level) /* {{{ */ myht = zend_get_properties_for(struc, ZEND_PROP_PURPOSE_DEBUG); class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc)); - - const char *prefix; - if (zend_object_is_lazy(Z_OBJ_P(struc))) { - if (zend_object_is_lazy_proxy(Z_OBJ_P(struc))) { - prefix = "lazy proxy "; - } else { - prefix = "lazy ghost "; - } - } else { - prefix = ""; - } + const char *prefix = php_var_dump_object_prefix(Z_OBJ_P(struc)); php_printf("%s%sobject(%s)#%d (%d) {\n", COMMON, prefix, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0); zend_string_release_ex(class_name, 0); @@ -374,17 +376,7 @@ PHPAPI void php_debug_zval_dump(zval *struc, int level) /* {{{ */ myht = zend_get_properties_for(struc, ZEND_PROP_PURPOSE_DEBUG); class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc)); - - const char *prefix; - if (zend_object_is_lazy(Z_OBJ_P(struc))) { - if (zend_object_is_lazy_proxy(Z_OBJ_P(struc))) { - prefix = "lazy proxy "; - } else { - prefix = "lazy ghost "; - } - } else { - prefix = ""; - } + const char *prefix = php_var_dump_object_prefix(Z_OBJ_P(struc)); php_printf("%sobject(%s)#%d (%d) refcount(%u){\n", prefix, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0, Z_REFCOUNT_P(struc)); zend_string_release_ex(class_name, 0); From 89c86562d7b504291db104c8fb637bc27a9f6c8e Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 16:47:50 +0200 Subject: [PATCH 19/56] Do not serialize as N; --- ext/standard/var.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/standard/var.c b/ext/standard/var.c index 8db4b2d755445..14af705b6331f 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -1232,7 +1232,7 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_ && zend_lazy_object_initialize_on_serialize(Z_OBJ_P(struc))) { obj = zend_lazy_object_init(Z_OBJ_P(struc)); if (!obj) { - smart_str_appendl(buf, "N;", 2); + ZEND_ASSERT(EG(exception)); return; } } From c9eec207875c71ae252bf7430d8d3a11efda103e Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 16:48:03 +0200 Subject: [PATCH 20/56] WS / naming --- ext/reflection/php_reflection.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index a45c78d64e85d..71de41937ce80 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -5259,7 +5259,7 @@ void reflection_class_new_lazy(INTERNAL_FUNCTION_PARAMETERS, PHP_METHOD(ReflectionClass, newLazyGhost) { reflection_class_new_lazy(INTERNAL_FUNCTION_PARAM_PASSTHRU, - ZEND_LAZY_OBJECT_STRATEGY_GHOST, /*is_make_lazy */ false); + ZEND_LAZY_OBJECT_STRATEGY_GHOST, /* is_reset */ false); } /* }}} */ @@ -5267,7 +5267,7 @@ PHP_METHOD(ReflectionClass, newLazyGhost) PHP_METHOD(ReflectionClass, newLazyProxy) { reflection_class_new_lazy(INTERNAL_FUNCTION_PARAM_PASSTHRU, - ZEND_LAZY_OBJECT_STRATEGY_PROXY, /*is_make_lazy */ false); + ZEND_LAZY_OBJECT_STRATEGY_PROXY, /* is_reset */ false); } /* }}} */ @@ -5283,7 +5283,7 @@ PHP_METHOD(ReflectionClass, resetAsLazyGhost) PHP_METHOD(ReflectionClass, resetAsLazyProxy) { reflection_class_new_lazy(INTERNAL_FUNCTION_PARAM_PASSTHRU, - ZEND_LAZY_OBJECT_STRATEGY_PROXY, /*is_reset */ true); + ZEND_LAZY_OBJECT_STRATEGY_PROXY, /* is_reset */ true); } /* }}} */ From 07331a48f79563ad044e1a665d2e4e33d795da99 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 17:29:53 +0200 Subject: [PATCH 21/56] Use zend_argument_error --- Zend/tests/lazy_objects/invalid_options.phpt | 43 ++++++++++++++++++++ ext/reflection/php_reflection.c | 4 +- 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/lazy_objects/invalid_options.phpt diff --git a/Zend/tests/lazy_objects/invalid_options.phpt b/Zend/tests/lazy_objects/invalid_options.phpt new file mode 100644 index 0000000000000..97b938c51a7a8 --- /dev/null +++ b/Zend/tests/lazy_objects/invalid_options.phpt @@ -0,0 +1,43 @@ +--TEST-- +Lazy objects: invalid options +--FILE-- +newLazyGhost(function ($obj) { }, -1); +} catch (ReflectionException $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +try { + $obj = $reflector->newLazyProxy(function ($obj) { }, -1); +} catch (ReflectionException $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +$obj = new C(); + +try { + $reflector->resetAsLazyGhost($obj, function ($obj) { }, -1); +} catch (ReflectionException $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +try { + $reflector->resetAsLazyProxy($obj, function ($obj) { }, -1); +} catch (ReflectionException $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +?> +--EXPECT-- +ReflectionException: ReflectionClass::newLazyGhost(): Argument #2 ($options) contains invalid flags +ReflectionException: ReflectionClass::newLazyProxy(): Argument #2 ($options) contains invalid flags +ReflectionException: ReflectionClass::resetAsLazyGhost(): Argument #3 ($options) contains invalid flags +ReflectionException: ReflectionClass::resetAsLazyProxy(): Argument #3 ($options) contains invalid flags diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 71de41937ce80..c0436a7c17925 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -5223,7 +5223,9 @@ void reflection_class_new_lazy(INTERNAL_FUNCTION_PARAMETERS, } if (options & ~ZEND_LAZY_OBJECT_USER_FLAGS) { - zend_throw_exception_ex(reflection_exception_ptr, 0, "Invalid options"); + uint32_t arg_num = 2 + is_reset; + zend_argument_error(reflection_exception_ptr, arg_num, + "contains invalid flags"); RETURN_THROWS(); } From 2c740fd0bd28ce263bb6ed8c8c606a955f9614ce Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 17:41:13 +0200 Subject: [PATCH 22/56] De-dup --- Zend/zend_API.c | 2 +- Zend/zend_compile.h | 9 ++++++++- Zend/zend_lazy_objects.c | 18 ++++++++---------- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 1d10f61e62175..aa6e15b633334 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1795,7 +1795,7 @@ ZEND_API void object_properties_load(zend_object *object, HashTable *properties) * calling zend_merge_properties(). */ static zend_always_inline zend_result _object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties) /* {{{ */ { - if (UNEXPECTED(class_type->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS|ZEND_ACC_ENUM))) { + if (UNEXPECTED(class_type->ce_flags & ZEND_ACC_UNINSTANTIABLE)) { if (class_type->ce_flags & ZEND_ACC_INTERFACE) { zend_throw_error(NULL, "Cannot instantiate interface %s", ZSTR_VAL(class_type->name)); } else if (class_type->ce_flags & ZEND_ACC_TRAIT) { diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 92a31764a89f8..0f7c39676c614 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -398,7 +398,6 @@ typedef struct _zend_oparray_context { /* op_array uses strict mode types | | | */ #define ZEND_ACC_STRICT_TYPES (1U << 31) /* | X | | */ - #define ZEND_ACC_PPP_MASK (ZEND_ACC_PUBLIC | ZEND_ACC_PROTECTED | ZEND_ACC_PRIVATE) #define ZEND_ACC_PPP_SET_MASK (ZEND_ACC_PUBLIC_SET | ZEND_ACC_PROTECTED_SET | ZEND_ACC_PRIVATE_SET) @@ -418,6 +417,14 @@ static zend_always_inline uint32_t zend_visibility_to_set_visibility(uint32_t vi /* call through internal function handler. e.g. Closure::invoke() */ #define ZEND_ACC_CALL_VIA_HANDLER ZEND_ACC_CALL_VIA_TRAMPOLINE +#define ZEND_ACC_UNINSTANTIABLE ( \ + ZEND_ACC_INTERFACE | \ + ZEND_ACC_TRAIT | \ + ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | \ + ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | \ + ZEND_ACC_ENUM \ +) + #define ZEND_SHORT_CIRCUITING_CHAIN_MASK 0x3 #define ZEND_SHORT_CIRCUITING_CHAIN_EXPR 0 #define ZEND_SHORT_CIRCUITING_CHAIN_ISSET 1 diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 84e26faccb418..4ac7a2dcc817b 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -207,18 +207,16 @@ ZEND_API zend_object *zend_object_make_lazy(zend_object *obj, int lazy_properties_count = 0; if (!obj) { - zval zobj; - if (UNEXPECTED(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS|ZEND_ACC_ENUM))) { - /* Slow path: use object_init_ex() */ - if (object_init_ex(&zobj, ce) == FAILURE) { - ZEND_ASSERT(EG(exception)); - return NULL; - } - obj = Z_OBJ(zobj); - } else { - obj = zend_objects_new(ce); + if (UNEXPECTED(ce->ce_flags & ZEND_ACC_UNINSTANTIABLE)) { + zval zobj; + /* Call object_init_ex() for the generated exception */ + zend_result result = object_init_ex(&zobj, ce); + ZEND_ASSERT(result == FAILURE && EG(exception)); + return NULL; } + obj = zend_objects_new(ce); + for (int i = 0; i < obj->ce->default_properties_count; i++) { zval *p = &obj->properties_table[i]; ZVAL_UNDEF(p); From 6f0a92728c3492aae6ca2eb56ac25c65e57fa01a Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 17:43:40 +0200 Subject: [PATCH 23/56] Improve naming: rename ce to reflection_ce --- Zend/zend_lazy_objects.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 4ac7a2dcc817b..6050f0c06c052 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -178,9 +178,9 @@ bool zend_lazy_object_decr_lazy_props(zend_object *obj) */ /* Make object 'obj' lazy. If 'obj' is NULL, create a lazy instance of - * class 'class_type' */ + * class 'reflection_ce' */ ZEND_API zend_object *zend_object_make_lazy(zend_object *obj, - zend_class_entry *ce, zval *initializer_zv, + zend_class_entry *reflection_ce, zval *initializer_zv, zend_fcall_info_cache *initializer_fcc, zend_lazy_object_flags_t flags) { ZEND_ASSERT(!(flags & ~(ZEND_LAZY_OBJECT_USER_FLAGS|ZEND_LAZY_OBJECT_STRATEGY_FLAGS))); @@ -188,18 +188,18 @@ ZEND_API zend_object *zend_object_make_lazy(zend_object *obj, || (flags & ZEND_LAZY_OBJECT_STRATEGY_FLAGS) == ZEND_LAZY_OBJECT_STRATEGY_PROXY); ZEND_ASSERT(!obj || (!zend_object_is_lazy(obj) || zend_lazy_object_initialized(obj))); - ZEND_ASSERT(!obj || instanceof_function(obj->ce, ce)); + ZEND_ASSERT(!obj || instanceof_function(obj->ce, reflection_ce)); /* Internal classes are not supported */ - if (UNEXPECTED(ce->type == ZEND_INTERNAL_CLASS && ce != zend_standard_class_def)) { - zend_throw_error(NULL, "Cannot make instance of internal class lazy: %s is internal", ZSTR_VAL(ce->name)); + if (UNEXPECTED(reflection_ce->type == ZEND_INTERNAL_CLASS && reflection_ce != zend_standard_class_def)) { + zend_throw_error(NULL, "Cannot make instance of internal class lazy: %s is internal", ZSTR_VAL(reflection_ce->name)); return NULL; } - for (zend_class_entry *parent = ce->parent; parent; parent = parent->parent) { + for (zend_class_entry *parent = reflection_ce->parent; parent; parent = parent->parent) { if (UNEXPECTED(parent->type == ZEND_INTERNAL_CLASS && parent != zend_standard_class_def)) { zend_throw_error(NULL, "Cannot make instance of internal class lazy: %s inherits internal class %s", - ZSTR_VAL(ce->name), ZSTR_VAL(parent->name)); + ZSTR_VAL(reflection_ce->name), ZSTR_VAL(parent->name)); return NULL; } } @@ -207,15 +207,15 @@ ZEND_API zend_object *zend_object_make_lazy(zend_object *obj, int lazy_properties_count = 0; if (!obj) { - if (UNEXPECTED(ce->ce_flags & ZEND_ACC_UNINSTANTIABLE)) { + if (UNEXPECTED(reflection_ce->ce_flags & ZEND_ACC_UNINSTANTIABLE)) { zval zobj; /* Call object_init_ex() for the generated exception */ - zend_result result = object_init_ex(&zobj, ce); + zend_result result = object_init_ex(&zobj, reflection_ce); ZEND_ASSERT(result == FAILURE && EG(exception)); return NULL; } - obj = zend_objects_new(ce); + obj = zend_objects_new(reflection_ce); for (int i = 0; i < obj->ce->default_properties_count; i++) { zval *p = &obj->properties_table[i]; @@ -253,7 +253,7 @@ ZEND_API zend_object *zend_object_make_lazy(zend_object *obj, obj->properties = NULL; /* unset() declared properties */ - for (int i = 0; i < ce->default_properties_count; i++) { + for (int i = 0; i < reflection_ce->default_properties_count; i++) { zend_property_info *prop_info = obj->ce->properties_info_table[i]; if (EXPECTED(prop_info)) { zval *p = &obj->properties_table[i]; From 3a3b755f8cef1cce4b454d655930b917180beb5e Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 17:46:10 +0200 Subject: [PATCH 24/56] RETURN_THROWS / RETURN_NULL --- ext/reflection/php_reflection.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index c0436a7c17925..e3d48306568af 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -5353,7 +5353,7 @@ ZEND_METHOD(ReflectionClass, markLazyObjectAsInitialized) if (zend_lazy_object_initialized(object)) { RETURN_OBJ_COPY(zend_lazy_object_get_instance(object)); } else { - ZEND_ASSERT(EG(exception)); + RETURN_THROWS(); } } /* }}} */ @@ -5373,7 +5373,7 @@ ZEND_METHOD(ReflectionClass, getLazyInitializer) if (!zend_object_is_lazy(object) || zend_lazy_object_initialized(object)) { - return; + RETURN_NULL(); } RETURN_ZVAL(zend_lazy_object_get_initializer_zv(object), 1, 0); From 0e24294eff83bef61f400b97353fdfde807cdfb0 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 17:54:40 +0200 Subject: [PATCH 25/56] Fallback in case zend_std_write_property is overridden --- Zend/zend_lazy_objects.c | 16 ++++++++++++++++ Zend/zend_lazy_objects.h | 1 + ext/reflection/php_reflection.c | 24 ++++++++++++++---------- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 6050f0c06c052..5b0e0ff4a856d 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -177,6 +177,22 @@ bool zend_lazy_object_decr_lazy_props(zend_object *obj) * Making objects lazy */ +ZEND_API bool zend_class_can_be_lazy(zend_class_entry *ce) +{ + /* Internal classes are not supported */ + if (UNEXPECTED(ce->type == ZEND_INTERNAL_CLASS && ce != zend_standard_class_def)) { + return false; + } + + for (zend_class_entry *parent = ce->parent; parent; parent = parent->parent) { + if (UNEXPECTED(parent->type == ZEND_INTERNAL_CLASS && parent != zend_standard_class_def)) { + return false; + } + } + + return true; +} + /* Make object 'obj' lazy. If 'obj' is NULL, create a lazy instance of * class 'reflection_ce' */ ZEND_API zend_object *zend_object_make_lazy(zend_object *obj, diff --git a/Zend/zend_lazy_objects.h b/Zend/zend_lazy_objects.h index 87654b1396095..b7fd1a5140fb1 100644 --- a/Zend/zend_lazy_objects.h +++ b/Zend/zend_lazy_objects.h @@ -59,6 +59,7 @@ typedef struct _zend_lazy_objects_store { typedef struct _zend_fcall_info zend_fcall_info; typedef struct _zend_fcall_info_cache zend_fcall_info_cache; +ZEND_API bool zend_class_can_be_lazy(zend_class_entry *ce); 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); diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index e3d48306568af..a298b56b5627b 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6145,11 +6145,13 @@ ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization) Z_PARAM_ZVAL(value) } ZEND_PARSE_PARAMETERS_END(); - if (object->handlers->write_property != zend_std_write_property) { - zend_throw_exception_ex(reflection_exception_ptr, 0, - "Can not use setRawValueWithoutLazyInitialization on internal class %s", - ZSTR_VAL(intern->ce->name)); - RETURN_THROWS(); + if (UNEXPECTED(object->handlers->write_property != zend_std_write_property)) { + if (!zend_class_can_be_lazy(object->ce)) { + zend_throw_exception_ex(reflection_exception_ptr, 0, + "Can not use setRawValueWithoutLazyInitialization on internal class %s", + ZSTR_VAL(intern->ce->name)); + RETURN_THROWS(); + } } ZEND_ASSERT(IS_VALID_PROPERTY_OFFSET(ref->prop->offset)); @@ -6218,11 +6220,13 @@ ZEND_METHOD(ReflectionProperty, skipLazyInitialization) Z_PARAM_OBJ_OF_CLASS(object, intern->ce) } ZEND_PARSE_PARAMETERS_END(); - if (object->handlers->write_property != zend_std_write_property) { - zend_throw_exception_ex(reflection_exception_ptr, 0, - "Can not use skipLazyInitialization on internal class %s", - ZSTR_VAL(intern->ce->name)); - RETURN_THROWS(); + if (UNEXPECTED(object->handlers->write_property != zend_std_write_property)) { + if (!zend_class_can_be_lazy(object->ce)) { + zend_throw_exception_ex(reflection_exception_ptr, 0, + "Can not use skipLazyInitialization on internal class %s", + ZSTR_VAL(intern->ce->name)); + RETURN_THROWS(); + } } ZEND_ASSERT(IS_VALID_PROPERTY_OFFSET(ref->prop->offset)); From 2a57a75375fb1d42826e043c708b4fb4563ac2c1 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 17:56:33 +0200 Subject: [PATCH 26/56] Remove unreachable condition --- ext/reflection/php_reflection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index a298b56b5627b..4996f54339d31 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6162,7 +6162,7 @@ ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization) /* Do not trigger initialization */ Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_LAZY; - if (!ref->prop || !ref->prop->hooks || !ref->prop->hooks[ZEND_PROPERTY_HOOK_SET]) { + if (!ref->prop->hooks || !ref->prop->hooks[ZEND_PROPERTY_HOOK_SET]) { zend_update_property_ex(intern->ce, object, ref->unmangled_name, value); } else { zend_function *func = zend_get_property_hook_trampoline(ref->prop, ZEND_PROPERTY_HOOK_SET, ref->unmangled_name); From d92db6e85c769556e12a681086e3a6b4071cf545 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 18:01:22 +0200 Subject: [PATCH 27/56] Extract common logic for setRawValue / setRawValueWithoutLazyInitialization --- ext/reflection/php_reflection.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 4996f54339d31..a71bc335ba1cc 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6083,6 +6083,16 @@ ZEND_METHOD(ReflectionProperty, getRawValue) } } +static void reflection_property_set_raw_value(property_reference *ref, reflection_object *intern, zend_object *object, zval *value) +{ + if (!ref->prop || !ref->prop->hooks || !ref->prop->hooks[ZEND_PROPERTY_HOOK_SET]) { + zend_update_property_ex(intern->ce, object, ref->unmangled_name, value); + } else { + zend_function *func = zend_get_property_hook_trampoline(ref->prop, ZEND_PROPERTY_HOOK_SET, ref->unmangled_name); + zend_call_known_instance_method_with_1_params(func, object, NULL, value); + } +} + ZEND_METHOD(ReflectionProperty, setRawValue) { reflection_object *intern; @@ -6101,12 +6111,7 @@ ZEND_METHOD(ReflectionProperty, setRawValue) RETURN_THROWS(); } - if (!ref->prop || !ref->prop->hooks || !ref->prop->hooks[ZEND_PROPERTY_HOOK_SET]) { - zend_update_property_ex(intern->ce, Z_OBJ_P(object), ref->unmangled_name, value); - } else { - zend_function *func = zend_get_property_hook_trampoline(ref->prop, ZEND_PROPERTY_HOOK_SET, ref->unmangled_name); - zend_call_known_instance_method_with_1_params(func, Z_OBJ_P(object), NULL, value); - } + reflection_property_set_raw_value(ref, intern, Z_OBJ_P(object), value); } /* {{{ Set property value withtout triggering initializer while skipping hooks if any */ @@ -6162,12 +6167,7 @@ ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization) /* Do not trigger initialization */ Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_LAZY; - if (!ref->prop->hooks || !ref->prop->hooks[ZEND_PROPERTY_HOOK_SET]) { - zend_update_property_ex(intern->ce, object, ref->unmangled_name, value); - } else { - zend_function *func = zend_get_property_hook_trampoline(ref->prop, ZEND_PROPERTY_HOOK_SET, ref->unmangled_name); - zend_call_known_instance_method_with_1_params(func, object, NULL, value); - } + reflection_property_set_raw_value(ref, intern, object, value); /* Mark property as lazy again if an exception prevented update */ if (EG(exception) && Z_TYPE_P(var_ptr) == IS_UNDEF From 81bfdb1475056fc032dc1ce4029f6b834911b327 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 18:12:15 +0200 Subject: [PATCH 28/56] Do not set prop as lazy after setRawValueWithoutLazyInitialization failure, if it was not originally lazy --- ...houtLazyInitialization_exception_001.phpt} | 0 ...thoutLazyInitialization_exception_002.phpt | 60 +++++++++++++++++++ ext/reflection/php_reflection.c | 2 +- 3 files changed, 61 insertions(+), 1 deletion(-) rename Zend/tests/lazy_objects/{setRawValueWithoutLazyInitialization_exception.phpt => setRawValueWithoutLazyInitialization_exception_001.phpt} (100%) create mode 100644 Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_exception_002.phpt diff --git a/Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_exception.phpt b/Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_exception_001.phpt similarity index 100% rename from Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_exception.phpt rename to Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_exception_001.phpt diff --git a/Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_exception_002.phpt b/Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_exception_002.phpt new file mode 100644 index 0000000000000..40221269893bd --- /dev/null +++ b/Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_exception_002.phpt @@ -0,0 +1,60 @@ +--TEST-- +Lazy objects: setRawValueWithoutLazyInitialization() leaves non-lazy properties as non-lazy in case of exception +--FILE-- +getProperty('a')->skipLazyInitialization($obj); + try { + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, new stdClass); + } catch (Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + + // Prop is still non-lazy: This does not trigger initialization + $obj->a = 1; + var_dump($reflector->isUninitializedLazyObject($obj)); + var_dump($obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function ($obj) { + throw new Exception('Unreachable'); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + throw new Exception('Unreachable'); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +TypeError: Cannot assign stdClass to property C::$a of type int +bool(true) +lazy ghost object(C)#%d (1) { + ["a"]=> + int(1) + ["b"]=> + uninitialized(int) +} +# Proxy +TypeError: Cannot assign stdClass to property C::$a of type int +bool(true) +lazy proxy object(C)#%d (1) { + ["a"]=> + int(1) + ["b"]=> + uninitialized(int) +} diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index a71bc335ba1cc..8ca80e19c455e 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6170,7 +6170,7 @@ ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization) reflection_property_set_raw_value(ref, intern, object, value); /* Mark property as lazy again if an exception prevented update */ - if (EG(exception) && Z_TYPE_P(var_ptr) == IS_UNDEF + if (EG(exception) && prop_was_lazy && Z_TYPE_P(var_ptr) == IS_UNDEF && zend_object_is_lazy(object) && !zend_lazy_object_initialized(object)) { Z_PROP_FLAG_P(var_ptr) |= IS_PROP_LAZY; From eace7108b9b2267a99e60b8554e2c6e104471767 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 18:20:54 +0200 Subject: [PATCH 29/56] Extract common logic between setRawValueWithoutLazyInitialization / skipLazyInitialization --- ext/reflection/php_reflection.c | 99 ++++++++++++++------------------- 1 file changed, 43 insertions(+), 56 deletions(-) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 8ca80e19c455e..32f129e5e7547 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6114,53 +6114,67 @@ ZEND_METHOD(ReflectionProperty, setRawValue) reflection_property_set_raw_value(ref, intern, Z_OBJ_P(object), value); } -/* {{{ Set property value withtout triggering initializer while skipping hooks if any */ -ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization) +static zend_result reflection_property_check_lazy_compatible(reflection_object *intern, + property_reference *ref, zend_object *object, const char *method) { - reflection_object *intern; - property_reference *ref; - zend_object *object; - zval *value; - - GET_REFLECTION_OBJECT_PTR(ref); - if (!ref->prop) { zend_throw_exception_ex(reflection_exception_ptr, 0, - "Can not use setRawValueWithoutLazyInitialization on dynamic property %s::$%s", - ZSTR_VAL(intern->ce->name), ZSTR_VAL(ref->unmangled_name)); - RETURN_THROWS(); + "Can not use %s on dynamic property %s::$%s", + method, ZSTR_VAL(intern->ce->name), + ZSTR_VAL(ref->unmangled_name)); + return FAILURE; } if (ref->prop->flags & ZEND_ACC_STATIC) { zend_throw_exception_ex(reflection_exception_ptr, 0, - "Can not use setRawValueWithoutLazyInitialization on static property %s::$%s", - ZSTR_VAL(intern->ce->name), ZSTR_VAL(ref->unmangled_name)); - RETURN_THROWS(); + "Can not use %s on static property %s::$%s", + method, ZSTR_VAL(intern->ce->name), + ZSTR_VAL(ref->unmangled_name)); + return FAILURE; } if (ref->prop->flags & ZEND_ACC_VIRTUAL) { zend_throw_exception_ex(reflection_exception_ptr, 0, - "Can not use setRawValueWithoutLazyInitialization on virtual property %s::$%s", - ZSTR_VAL(intern->ce->name), ZSTR_VAL(ref->unmangled_name)); - RETURN_THROWS(); + "Can not use %s on virtual property %s::$%s", + method, ZSTR_VAL(intern->ce->name), + ZSTR_VAL(ref->unmangled_name)); + return FAILURE; } - ZEND_PARSE_PARAMETERS_START(2, 2) { - Z_PARAM_OBJ_OF_CLASS(object, intern->ce) - Z_PARAM_ZVAL(value) - } ZEND_PARSE_PARAMETERS_END(); - if (UNEXPECTED(object->handlers->write_property != zend_std_write_property)) { if (!zend_class_can_be_lazy(object->ce)) { zend_throw_exception_ex(reflection_exception_ptr, 0, - "Can not use setRawValueWithoutLazyInitialization on internal class %s", - ZSTR_VAL(intern->ce->name)); - RETURN_THROWS(); + "Can not use %s on internal class %s", + method, ZSTR_VAL(intern->ce->name)); + return FAILURE; } } ZEND_ASSERT(IS_VALID_PROPERTY_OFFSET(ref->prop->offset)); + return SUCCESS; +} + +/* {{{ Set property value withtout triggering initializer while skipping hooks if any */ +ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization) +{ + reflection_object *intern; + property_reference *ref; + zend_object *object; + zval *value; + + GET_REFLECTION_OBJECT_PTR(ref); + + ZEND_PARSE_PARAMETERS_START(2, 2) { + Z_PARAM_OBJ_OF_CLASS(object, intern->ce) + Z_PARAM_ZVAL(value) + } ZEND_PARSE_PARAMETERS_END(); + + if (reflection_property_check_lazy_compatible(intern, ref, object, + "setRawValueWithoutLazyInitialization") == FAILURE) { + RETURN_THROWS(); + } + zval *var_ptr = OBJ_PROP(object, ref->prop->offset); bool prop_was_lazy = Z_PROP_FLAG_P(var_ptr) & IS_PROP_LAZY; @@ -6195,42 +6209,15 @@ ZEND_METHOD(ReflectionProperty, skipLazyInitialization) GET_REFLECTION_OBJECT_PTR(ref); - if (!ref->prop) { - zend_throw_exception_ex(reflection_exception_ptr, 0, - "Can not use skipLazyInitialization on dynamic property %s::$%s", - ZSTR_VAL(intern->ce->name), ZSTR_VAL(ref->unmangled_name)); - RETURN_THROWS(); - } - - if (ref->prop->flags & ZEND_ACC_STATIC) { - zend_throw_exception_ex(reflection_exception_ptr, 0, - "Can not use skipLazyInitialization on static property %s::$%s", - ZSTR_VAL(intern->ce->name), ZSTR_VAL(ref->unmangled_name)); - RETURN_THROWS(); - } - - if (ref->prop->flags & ZEND_ACC_VIRTUAL) { - zend_throw_exception_ex(reflection_exception_ptr, 0, - "Can not use skipLazyInitialization on virtual property %s::$%s", - ZSTR_VAL(intern->ce->name), ZSTR_VAL(ref->unmangled_name)); - RETURN_THROWS(); - } - ZEND_PARSE_PARAMETERS_START(1, 1) { Z_PARAM_OBJ_OF_CLASS(object, intern->ce) } ZEND_PARSE_PARAMETERS_END(); - if (UNEXPECTED(object->handlers->write_property != zend_std_write_property)) { - if (!zend_class_can_be_lazy(object->ce)) { - zend_throw_exception_ex(reflection_exception_ptr, 0, - "Can not use skipLazyInitialization on internal class %s", - ZSTR_VAL(intern->ce->name)); - RETURN_THROWS(); - } + if (reflection_property_check_lazy_compatible(intern, ref, object, + "skipLazyInitialization") == FAILURE) { + RETURN_THROWS(); } - ZEND_ASSERT(IS_VALID_PROPERTY_OFFSET(ref->prop->offset)); - bool prop_was_lazy = (Z_PROP_FLAG_P(OBJ_PROP(object, ref->prop->offset)) & IS_PROP_LAZY); zval *src = &object->ce->default_properties_table[OBJ_PROP_TO_NUM(ref->prop->offset)]; From db0bf616c2f87ebeb01398aff615f38e5402b2d5 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 18:26:59 +0200 Subject: [PATCH 30/56] Use ZVAL_COPY_PROP --- ext/reflection/php_reflection.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 32f129e5e7547..fa149a36a02b9 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6230,8 +6230,7 @@ ZEND_METHOD(ReflectionProperty, skipLazyInitialization) ZEND_ASSERT(Z_TYPE_P(dst) == IS_UNDEF && "Lazy property should be UNDEF"); - ZVAL_COPY_OR_DUP_PROP(dst, src); - Z_PROP_FLAG_P(dst) &= ~(IS_PROP_LAZY | IS_PROP_REINITABLE); + ZVAL_COPY_PROP(dst, src); /* Object becomes non-lazy if this was the last lazy prop */ if (prop_was_lazy && zend_object_is_lazy(object) From e5af928a635d8a939812c987a5f3e6b3f81727fb Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 18:39:10 +0200 Subject: [PATCH 31/56] Add comment / extract logic --- Zend/zend_object_handlers.h | 13 +++++++++++++ Zend/zend_operators.c | 5 +---- Zend/zend_vm_def.h | 5 +---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index e392aefbfd5cb..418a93de3ccd2 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -290,6 +290,19 @@ static zend_always_inline HashTable *zend_std_get_properties_ex(zend_object *obj /* Implements the fast path for array cast */ ZEND_API HashTable *zend_std_build_object_properties_array(zend_object *zobj); +#define ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(object) ( \ + /* We can use zend_std_build_object_properties_array() for objects \ + * without properties ht and with standard handlers */ \ + Z_OBJ_P(object)->properties == NULL \ + && Z_OBJ_HT_P(object)->get_properties_for == NULL \ + && Z_OBJ_HT_P(object)->get_properties == zend_std_get_properties \ + /* For initialized proxies we need to forward to the real instance */ \ + && ( \ + !zend_object_is_lazy_proxy(Z_OBJ_P(object)) \ + || !zend_lazy_object_initialized(Z_OBJ_P(object)) \ + ) \ +) + /* Handler for objects that cannot be meaningfully compared. * Only objects with the same identity will be considered equal. */ ZEND_API int zend_objects_not_comparable(zval *o1, zval *o2); diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index a3446bdcc4a99..ae75e95a71c1d 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -812,10 +812,7 @@ ZEND_API void ZEND_FASTCALL convert_to_array(zval *op) /* {{{ */ case IS_OBJECT: if (Z_OBJCE_P(op) == zend_ce_closure) { convert_scalar_to_array(op); - } else if (Z_OBJ_P(op)->properties == NULL - && Z_OBJ_HT_P(op)->get_properties_for == NULL - && Z_OBJ_HT_P(op)->get_properties == zend_std_get_properties - && (!zend_object_is_lazy_proxy(Z_OBJ_P(op)) && !zend_lazy_object_initialized(Z_OBJ_P(op)))) { + } else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(op)) { /* Optimized version without rebuilding properties HashTable */ HashTable *ht = zend_std_build_object_properties_array(Z_OBJ_P(op)); OBJ_RELEASE(Z_OBJ_P(op)); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 772bc27869121..49bdd99189838 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -6429,10 +6429,7 @@ ZEND_VM_COLD_CONST_HANDLER(51, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE) } else { ZVAL_EMPTY_ARRAY(result); } - } else if (Z_OBJ_P(expr)->properties == NULL - && Z_OBJ_HT_P(expr)->get_properties_for == NULL - && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties - && (!zend_object_is_lazy_proxy(Z_OBJ_P(expr)) || !zend_lazy_object_initialized(Z_OBJ_P(expr)))) { + } else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(expr)) { /* Optimized version without rebuilding properties HashTable */ ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); } else { From 7b4545fee49f6f1c4906419c9b24b386d0cc6690 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 18:50:21 +0200 Subject: [PATCH 32/56] Add test --- Zend/tests/lazy_objects/convert_to_array.phpt | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 Zend/tests/lazy_objects/convert_to_array.phpt diff --git a/Zend/tests/lazy_objects/convert_to_array.phpt b/Zend/tests/lazy_objects/convert_to_array.phpt new file mode 100644 index 0000000000000..72eb3fd4f670e --- /dev/null +++ b/Zend/tests/lazy_objects/convert_to_array.phpt @@ -0,0 +1,93 @@ +--TEST-- +Lazy objects: Convertion to array +--FILE-- +a = 1; + $this->b = 2; + } +} + +function test(string $name, object $obj) { + printf("# %s\n", $name); + + $reflector = new ReflectionClass(C::class); + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, 3); + + $a = []; + // Converts $obj to array internally + array_splice($a, 0, 0, $obj); + var_dump($a, $obj); + + $reflector->initializeLazyObject($obj); + + $a = []; + array_splice($a, 0, 0, $obj); + var_dump($a, $obj); +} + +$reflector = new ReflectionClass(C::class); +$obj = $reflector->newLazyGhost(function ($obj) { + $obj->__construct(); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + return new C(); +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +array(1) { + [0]=> + int(3) +} +lazy ghost object(C)#%d (1) { + ["a"]=> + int(3) +} +array(2) { + [0]=> + int(1) + [1]=> + int(2) +} +object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + int(2) +} +# Proxy +array(1) { + [0]=> + int(3) +} +lazy proxy object(C)#%d (1) { + ["a"]=> + int(3) +} +array(2) { + [0]=> + int(1) + [1]=> + int(2) +} +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + int(2) + } +} From 8415e9d611f7ef9f9bbd6e0be40e0ef776f80bd8 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 18:53:13 +0200 Subject: [PATCH 33/56] Rename IS_OBJ_LAZY -> IS_OBJ_LAZY_UNINITIALIZED --- Zend/zend_lazy_objects.c | 28 ++++++++++++++-------------- Zend/zend_lazy_objects.h | 4 ++-- Zend/zend_types.h | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 5b0e0ff4a856d..0bd1c73bfb0fa 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -95,7 +95,7 @@ void zend_lazy_objects_destroy(zend_lazy_objects_store *store) void zend_lazy_object_set_info(zend_object *obj, zend_lazy_object_info *info) { - ZEND_ASSERT(OBJ_EXTRA_FLAGS(obj) & (IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY)); + ZEND_ASSERT(OBJ_EXTRA_FLAGS(obj) & (IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY)); zval *zv = zend_hash_index_add_new_ptr(&EG(lazy_objects_store).infos, obj->handle, info); ZEND_ASSERT(zv); @@ -103,7 +103,7 @@ void zend_lazy_object_set_info(zend_object *obj, zend_lazy_object_info *info) zend_lazy_object_info* zend_lazy_object_get_info(zend_object *obj) { - ZEND_ASSERT(OBJ_EXTRA_FLAGS(obj) & (IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY)); + ZEND_ASSERT(OBJ_EXTRA_FLAGS(obj) & (IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY)); zend_lazy_object_info *info = zend_hash_index_find_ptr(&EG(lazy_objects_store).infos, obj->handle); ZEND_ASSERT(info); @@ -246,7 +246,7 @@ ZEND_API zend_object *zend_object_make_lazy(zend_object *obj, } else { if (zend_object_is_lazy(obj)) { ZEND_ASSERT(zend_object_is_lazy_proxy(obj) && zend_lazy_object_initialized(obj)); - OBJ_EXTRA_FLAGS(obj) &= ~(IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY); + OBJ_EXTRA_FLAGS(obj) &= ~(IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY); zend_lazy_object_del_info(obj); } else if (!(flags & ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR) && !(OBJ_FLAGS(obj) & IS_OBJ_DESTRUCTOR_CALLED)) { @@ -294,7 +294,7 @@ ZEND_API zend_object *zend_object_make_lazy(zend_object *obj, return obj; } - OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY; + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED; if (flags & ZEND_LAZY_OBJECT_STRATEGY_PROXY) { OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_PROXY; @@ -335,7 +335,7 @@ ZEND_API zend_object *zend_lazy_object_mark_as_initialized(zend_object *obj) zval *default_properties_table = CE_DEFAULT_PROPERTIES_TABLE(ce); zval *properties_table = obj->properties_table; - OBJ_EXTRA_FLAGS(obj) &= ~(IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY); + OBJ_EXTRA_FLAGS(obj) &= ~(IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY); for (int i = 0; i < ce->default_properties_count; i++) { if (Z_PROP_FLAG_P(&properties_table[i]) & IS_PROP_LAZY) { @@ -385,7 +385,7 @@ static void zend_lazy_object_revert_init(zend_object *obj, zval *properties_tabl obj->properties = NULL; } - OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY; + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED; } static bool zend_lazy_object_compatible(zend_object *real_object, zend_object *lazy_object) @@ -418,7 +418,7 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj) zend_lazy_object_info *info = zend_lazy_object_get_info(obj); /* prevent reentrant initialization */ - OBJ_EXTRA_FLAGS(obj) &= ~(IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY); + OBJ_EXTRA_FLAGS(obj) &= ~(IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY); /* Call factory */ zval retval; @@ -432,12 +432,12 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj) zend_call_known_fcc(initializer, &retval, argc, &zobj, named_params); if (UNEXPECTED(EG(exception))) { - OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY; + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY; return NULL; } if (UNEXPECTED(Z_TYPE(retval) != IS_OBJECT || !zend_lazy_object_compatible(Z_OBJ(retval), obj))) { - OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY; + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY; zend_type_error("The real instance class %s is not compatible with the proxy class %s. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor or __clone methods.", zend_zval_value_name(&retval), ZSTR_VAL(obj->ce->name)); @@ -446,7 +446,7 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj) } if (UNEXPECTED(Z_OBJ(retval) == obj || zend_object_is_lazy(Z_OBJ(retval)))) { - OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY; + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY; zend_throw_error(NULL, "Lazy proxy factory must return a non-lazy object"); zval_ptr_dtor(&retval); return NULL; @@ -458,7 +458,7 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj) zend_object *clone = Z_OBJ_HT(retval)->clone_obj(Z_OBJ(retval)); if (EG(exception)) { - OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY; + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY; zval_ptr_dtor(&retval); OBJ_RELEASE(clone); return NULL; @@ -467,7 +467,7 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj) ZEND_ASSERT(zend_lazy_object_compatible(clone, obj)); if (zend_object_is_lazy(clone)) { - OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY|IS_OBJ_LAZY_PROXY; + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY; zend_throw_error(NULL, "Lazy proxy factory must return a non-lazy object"); zval_ptr_dtor(&retval); return NULL; @@ -533,7 +533,7 @@ ZEND_API zend_object *zend_lazy_object_init(zend_object *obj) zend_fcall_info_cache *initializer = zend_lazy_object_get_initializer_fcc(obj); /* Prevent reentrant initialization */ - OBJ_EXTRA_FLAGS(obj) &= ~IS_OBJ_LAZY; + OBJ_EXTRA_FLAGS(obj) &= ~IS_OBJ_LAZY_UNINITIALIZED; /* Snapshot dynamic properties */ HashTable *properties_snapshot = obj->properties; @@ -614,7 +614,7 @@ void zend_lazy_object_realize(zend_object *obj) } #endif - OBJ_EXTRA_FLAGS(obj) &= ~(IS_OBJ_LAZY | IS_OBJ_LAZY_PROXY); + OBJ_EXTRA_FLAGS(obj) &= ~(IS_OBJ_LAZY_UNINITIALIZED | IS_OBJ_LAZY_PROXY); } /* Initialize object and clone it. For proxies, we clone both the proxy and its diff --git a/Zend/zend_lazy_objects.h b/Zend/zend_lazy_objects.h index b7fd1a5140fb1..f042b056980df 100644 --- a/Zend/zend_lazy_objects.h +++ b/Zend/zend_lazy_objects.h @@ -81,7 +81,7 @@ void zend_lazy_object_realize(zend_object *obj); static zend_always_inline bool zend_object_is_lazy(zend_object *obj) { - return (OBJ_EXTRA_FLAGS(obj) & (IS_OBJ_LAZY | IS_OBJ_LAZY_PROXY)); + return (OBJ_EXTRA_FLAGS(obj) & (IS_OBJ_LAZY_UNINITIALIZED | IS_OBJ_LAZY_PROXY)); } static zend_always_inline bool zend_object_is_lazy_proxy(zend_object *obj) @@ -91,7 +91,7 @@ static zend_always_inline bool zend_object_is_lazy_proxy(zend_object *obj) static zend_always_inline bool zend_lazy_object_initialized(zend_object *obj) { - return !(OBJ_EXTRA_FLAGS(obj) & IS_OBJ_LAZY); + return !(OBJ_EXTRA_FLAGS(obj) & IS_OBJ_LAZY_UNINITIALIZED); } /* True if accessing a lazy prop on obj mandates a call to diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 00c4b652988a5..8f012868ddab4 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -832,7 +832,7 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) { /* object extra flags (zend_object.flags) */ -#define IS_OBJ_LAZY (1U<<31) /* Virtual proxy or uninitialized Ghost */ +#define IS_OBJ_LAZY_UNINITIALIZED (1U<<31) /* Virtual proxy or uninitialized Ghost */ #define IS_OBJ_LAZY_PROXY (1U<<30) /* Virtual proxy (may be initialized) */ #define OBJ_EXTRA_FLAGS(obj) ((obj)->extra_flags) From e85595c5b304a443d9f8a5cd0994847b7444853e Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 18:54:19 +0200 Subject: [PATCH 34/56] Early return --- Zend/zend_objects.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index 3c824702e95f8..348b3f3416b91 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -309,20 +309,20 @@ ZEND_API zend_object *zend_objects_clone_obj(zend_object *old_object) if (UNEXPECTED(zend_object_is_lazy(old_object))) { return zend_lazy_object_clone(old_object); - } else { - /* assume that create isn't overwritten, so when clone depends on the - * overwritten one then it must itself be overwritten */ - new_object = zend_objects_new(old_object->ce); - - /* zend_objects_clone_members() expect the properties to be initialized. */ - if (new_object->ce->default_properties_count) { - zval *p = new_object->properties_table; - zval *end = p + new_object->ce->default_properties_count; - do { - ZVAL_UNDEF(p); - p++; - } while (p != end); - } + } + + /* assume that create isn't overwritten, so when clone depends on the + * overwritten one then it must itself be overwritten */ + new_object = zend_objects_new(old_object->ce); + + /* zend_objects_clone_members() expect the properties to be initialized. */ + if (new_object->ce->default_properties_count) { + zval *p = new_object->properties_table; + zval *end = p + new_object->ce->default_properties_count; + do { + ZVAL_UNDEF(p); + p++; + } while (p != end); } zend_objects_clone_members(new_object, old_object); From bf20f0a91d713caabc430df4ba879a558a5cbd16 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 19:10:55 +0200 Subject: [PATCH 35/56] Fix null pointer deref --- Zend/tests/lazy_objects/get_properties.phpt | 27 +++++++++++++++++++++ Zend/zend_object_handlers.h | 6 +++-- 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 Zend/tests/lazy_objects/get_properties.phpt diff --git a/Zend/tests/lazy_objects/get_properties.phpt b/Zend/tests/lazy_objects/get_properties.phpt new file mode 100644 index 0000000000000..38b752c2f8b5b --- /dev/null +++ b/Zend/tests/lazy_objects/get_properties.phpt @@ -0,0 +1,27 @@ +--TEST-- +Lazy objects: get_properties failure +--FILE-- +newLazyProxy(function () { + throw new \Exception('Initializer'); +}); + +$b = new C(); + +try { + var_dump($a > $b); +} catch (Exception $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + +?> +--EXPECT-- +Exception: Initializer diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index 418a93de3ccd2..add97f47c0ef1 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -276,10 +276,12 @@ ZEND_API HashTable *rebuild_object_properties_internal(zend_object *zobj); static zend_always_inline HashTable *zend_std_get_properties_ex(zend_object *object) { if (UNEXPECTED(zend_lazy_object_must_init(object))) { - object = zend_lazy_object_init(object); - if (UNEXPECTED(!object)) { + zend_object *tmp = zend_lazy_object_init(object); + if (UNEXPECTED(!tmp)) { + ZEND_ASSERT(!object->properties || object->properties == &zend_empty_array); return object->properties = (zend_array*) &zend_empty_array; } + object = tmp; } if (!object->properties) { return rebuild_object_properties_internal(object); From f8867263447f6118a2548036e0fa90d7416cb885 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 19:11:17 +0200 Subject: [PATCH 36/56] Fix comparison of lazy objects --- .../lazy_objects/init_trigger_compare.phpt | 54 +++++++++++++++++++ Zend/zend_object_handlers.c | 3 +- 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/lazy_objects/init_trigger_compare.phpt diff --git a/Zend/tests/lazy_objects/init_trigger_compare.phpt b/Zend/tests/lazy_objects/init_trigger_compare.phpt new file mode 100644 index 0000000000000..bebd5e9c5f0c7 --- /dev/null +++ b/Zend/tests/lazy_objects/init_trigger_compare.phpt @@ -0,0 +1,54 @@ +--TEST-- +Lazy objects: comparison initializes object +--FILE-- +newLazyGhost(function ($obj) { + $obj->__construct(); +}); + +$b = $reflector->newLazyProxy(function ($obj) { + return new C(); +}); + +var_dump($a > $b); + +$a = $reflector->newLazyGhost(function ($obj) { + $obj->__construct(); +}); + +$b = $reflector->newLazyProxy(function ($obj) { + return new C(); +}); + +var_dump($a == $b); + +$a = $reflector->newLazyGhost(function ($obj) { + $obj->__construct(); +}); + +var_dump('A' < $a); +?> +--EXPECT-- +string(14) "C::__construct" +string(14) "C::__construct" +bool(false) +string(14) "C::__construct" +string(14) "C::__construct" +bool(true) +bool(true) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 345772fc2083a..91cea49220842 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -2072,7 +2072,8 @@ ZEND_API int zend_std_compare_objects(zval *o1, zval *o2) /* {{{ */ if (zobj1->ce != zobj2->ce) { return ZEND_UNCOMPARABLE; /* different classes */ } - if (!zobj1->properties && !zobj2->properties) { + if (!zobj1->properties && !zobj2->properties + && !zend_object_is_lazy(zobj1) && !zend_object_is_lazy(zobj2)) { zend_property_info *info; int i; From f8df7ae136166ba755fdff5a2b7974b7560dfca0 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 19:58:59 +0200 Subject: [PATCH 37/56] Skip zend_std_get_properties() --- Zend/zend_object_handlers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 91cea49220842..8a973f4fc0927 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1384,7 +1384,7 @@ ZEND_API zval *zend_std_get_property_ptr_ptr(zend_object *zobj, zend_string *nam if (UNEXPECTED(type == BP_VAR_RW || type == BP_VAR_R)) { zend_error(E_WARNING, "Undefined property: %s::$%s", ZSTR_VAL(zobj->ce->name), ZSTR_VAL(name)); } - retval = zend_hash_add(zend_std_get_properties(zobj), name, &EG(uninitialized_zval)); + retval = zend_hash_add(zobj->properties, name, &EG(uninitialized_zval)); } } else if (!IS_HOOKED_PROPERTY_OFFSET(property_offset) && zobj->ce->__get == NULL) { retval = &EG(error_zval); From 23e1a4bb6b1cb1678cad0c1e2672d4b7ef6094b9 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 20:00:49 +0200 Subject: [PATCH 38/56] Remove dead code for clone handling --- Zend/zend_lazy_objects.c | 25 ------------------------- Zend/zend_lazy_objects.h | 3 --- 2 files changed, 28 deletions(-) diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 0bd1c73bfb0fa..0472e826a50bb 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -452,31 +452,6 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj) return NULL; } - if (info->flags & ZEND_LAZY_OBJECT_CLONE) { - /* For uninitialized lazy proxies, cloning of the real instance is - * postponed until initialization */ - - zend_object *clone = Z_OBJ_HT(retval)->clone_obj(Z_OBJ(retval)); - if (EG(exception)) { - OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY; - zval_ptr_dtor(&retval); - OBJ_RELEASE(clone); - return NULL; - } - - ZEND_ASSERT(zend_lazy_object_compatible(clone, obj)); - - if (zend_object_is_lazy(clone)) { - OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY; - zend_throw_error(NULL, "Lazy proxy factory must return a non-lazy object"); - zval_ptr_dtor(&retval); - return NULL; - } - - zval_ptr_dtor(&retval); - ZVAL_OBJ(&retval, clone); - } - zend_fcc_dtor(&info->u.initializer.fcc); zval_ptr_dtor(&info->u.initializer.zv); info->u.instance = Z_OBJ(retval); diff --git a/Zend/zend_lazy_objects.h b/Zend/zend_lazy_objects.h index f042b056980df..d5eb20d7dcde7 100644 --- a/Zend/zend_lazy_objects.h +++ b/Zend/zend_lazy_objects.h @@ -36,9 +36,6 @@ /* Do not call destructor when making existing object lazy */ #define ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR (1<<4) -/* The object is a clone */ -#define ZEND_LAZY_OBJECT_CLONE (1<<5) - #define ZEND_LAZY_OBJECT_USER_FLAGS ( \ ZEND_LAZY_OBJECT_SKIP_INITIALIZATION_ON_SERIALIZE | \ ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR \ From 33acce5591d28f98edb7fc51cb3eb25ee097815f Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 20:09:03 +0200 Subject: [PATCH 39/56] newLazy*() do not accept SKIP_DESTRUCTOR --- Zend/tests/lazy_objects/invalid_options.phpt | 8 ++++++++ ext/reflection/php_reflection.c | 9 ++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Zend/tests/lazy_objects/invalid_options.phpt b/Zend/tests/lazy_objects/invalid_options.phpt index 97b938c51a7a8..96c965ec4175d 100644 --- a/Zend/tests/lazy_objects/invalid_options.phpt +++ b/Zend/tests/lazy_objects/invalid_options.phpt @@ -21,6 +21,13 @@ try { printf("%s: %s\n", $e::class, $e->getMessage()); } +try { + // SKIP_DESTRUCTOR is only allowed on resetAsLazyProxy() + $obj = $reflector->newLazyGhost(function ($obj) { }, ReflectionClass::SKIP_DESTRUCTOR); +} catch (ReflectionException $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} + $obj = new C(); try { @@ -39,5 +46,6 @@ try { --EXPECT-- ReflectionException: ReflectionClass::newLazyGhost(): Argument #2 ($options) contains invalid flags ReflectionException: ReflectionClass::newLazyProxy(): Argument #2 ($options) contains invalid flags +ReflectionException: ReflectionClass::newLazyGhost(): Argument #2 ($options) does not accept ReflectionClass::SKIP_DESTRUCTOR ReflectionException: ReflectionClass::resetAsLazyGhost(): Argument #3 ($options) contains invalid flags ReflectionException: ReflectionClass::resetAsLazyProxy(): Argument #3 ($options) contains invalid flags diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index fa149a36a02b9..b5c62e006639a 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -5222,13 +5222,20 @@ void reflection_class_new_lazy(INTERNAL_FUNCTION_PARAMETERS, obj = NULL; } - if (options & ~ZEND_LAZY_OBJECT_USER_FLAGS) { + zend_long accepted_flags = ZEND_LAZY_OBJECT_USER_FLAGS; + if (options & ~accepted_flags) { uint32_t arg_num = 2 + is_reset; zend_argument_error(reflection_exception_ptr, arg_num, "contains invalid flags"); RETURN_THROWS(); } + if (!is_reset && options & ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR) { + zend_argument_error(reflection_exception_ptr, 2, + "does not accept ReflectionClass::SKIP_DESTRUCTOR"); + RETURN_THROWS(); + } + 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"); From e25d16a9152b3a2fa1096275aa0e78e79cb79b56 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 20:59:15 +0200 Subject: [PATCH 40/56] Make functions static when possible --- Zend/zend_lazy_objects.c | 6 +++--- Zend/zend_lazy_objects.h | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 0472e826a50bb..8606d6aa9a93d 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -93,7 +93,7 @@ void zend_lazy_objects_destroy(zend_lazy_objects_store *store) zend_hash_destroy(&store->infos); } -void zend_lazy_object_set_info(zend_object *obj, zend_lazy_object_info *info) +static void zend_lazy_object_set_info(zend_object *obj, zend_lazy_object_info *info) { ZEND_ASSERT(OBJ_EXTRA_FLAGS(obj) & (IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY)); @@ -101,7 +101,7 @@ void zend_lazy_object_set_info(zend_object *obj, zend_lazy_object_info *info) ZEND_ASSERT(zv); } -zend_lazy_object_info* zend_lazy_object_get_info(zend_object *obj) +static zend_lazy_object_info* zend_lazy_object_get_info(zend_object *obj) { ZEND_ASSERT(OBJ_EXTRA_FLAGS(obj) & (IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY)); @@ -122,7 +122,7 @@ zval* zend_lazy_object_get_initializer_zv(zend_object *obj) return &info->u.initializer.zv; } -zend_fcall_info_cache* zend_lazy_object_get_initializer_fcc(zend_object *obj) +static zend_fcall_info_cache* zend_lazy_object_get_initializer_fcc(zend_object *obj) { ZEND_ASSERT(!zend_lazy_object_initialized(obj)); diff --git a/Zend/zend_lazy_objects.h b/Zend/zend_lazy_objects.h index d5eb20d7dcde7..a10e2205673a5 100644 --- a/Zend/zend_lazy_objects.h +++ b/Zend/zend_lazy_objects.h @@ -66,7 +66,6 @@ ZEND_API zend_object *zend_lazy_object_mark_as_initialized(zend_object *obj); void zend_lazy_objects_init(zend_lazy_objects_store *store); void zend_lazy_objects_destroy(zend_lazy_objects_store *store); zval* zend_lazy_object_get_initializer_zv(zend_object *obj); -zend_fcall_info_cache* zend_lazy_object_get_initializer_fcc(zend_object *obj); zend_object *zend_lazy_object_get_instance(zend_object *obj); zend_lazy_object_flags_t zend_lazy_object_get_flags(zend_object *obj); void zend_lazy_object_del_info(zend_object *obj); From a31e777e6113a0799a8e3f005f2a4e5e5594d131 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 21:00:17 +0200 Subject: [PATCH 41/56] Simplify assertions --- Zend/zend_lazy_objects.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 8606d6aa9a93d..3b82b733d00cf 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -95,7 +95,7 @@ void zend_lazy_objects_destroy(zend_lazy_objects_store *store) static void zend_lazy_object_set_info(zend_object *obj, zend_lazy_object_info *info) { - ZEND_ASSERT(OBJ_EXTRA_FLAGS(obj) & (IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY)); + ZEND_ASSERT(zend_object_is_lazy(obj)); zval *zv = zend_hash_index_add_new_ptr(&EG(lazy_objects_store).infos, obj->handle, info); ZEND_ASSERT(zv); @@ -103,7 +103,7 @@ static void zend_lazy_object_set_info(zend_object *obj, zend_lazy_object_info *i static zend_lazy_object_info* zend_lazy_object_get_info(zend_object *obj) { - ZEND_ASSERT(OBJ_EXTRA_FLAGS(obj) & (IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY)); + ZEND_ASSERT(zend_object_is_lazy(obj)); zend_lazy_object_info *info = zend_hash_index_find_ptr(&EG(lazy_objects_store).infos, obj->handle); ZEND_ASSERT(info); From 6cf649655d9705d2c48504dd7beb82fdc6ec5cb6 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 21:01:08 +0200 Subject: [PATCH 42/56] Prevent warning --- Zend/zend_lazy_objects.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 3b82b733d00cf..fb450a251d7a2 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -99,6 +99,7 @@ static void zend_lazy_object_set_info(zend_object *obj, zend_lazy_object_info *i zval *zv = zend_hash_index_add_new_ptr(&EG(lazy_objects_store).infos, obj->handle, info); ZEND_ASSERT(zv); + (void)zv; } static zend_lazy_object_info* zend_lazy_object_get_info(zend_object *obj) From 8841964146a6600bc5d4afacdcfb6cb853566f9b Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 21:07:02 +0200 Subject: [PATCH 43/56] Check final property --- Zend/zend_lazy_objects.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index fb450a251d7a2..72e752c3de5a3 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -276,7 +276,8 @@ ZEND_API zend_object *zend_object_make_lazy(zend_object *obj, zval *p = &obj->properties_table[i]; if (Z_TYPE_P(p) != IS_UNDEF) { if ((prop_info->flags & ZEND_ACC_READONLY) && !(Z_PROP_FLAG_P(p) & IS_PROP_REINITABLE) - && (obj->ce->ce_flags & ZEND_ACC_FINAL)) { + /* TODO: test final property */ + && ((obj->ce->ce_flags & ZEND_ACC_FINAL) || (prop_info->flags & ZEND_ACC_FINAL))) { continue; } zend_object_dtor_property(obj, p); From 77fe4fc8cfd2729ab9eeddd32e3d0d8ffd77c635 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 21:08:53 +0200 Subject: [PATCH 44/56] Avoid redundant addref/delref --- Zend/zend_lazy_objects.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 72e752c3de5a3..75ba3de07efe0 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -362,8 +362,7 @@ static void zend_lazy_object_revert_init(zend_object *obj, zval *properties_tabl for (int i = 0; i < ce->default_properties_count; i++) { zval *p = &properties_table[i]; zend_object_dtor_property(obj, p); - ZVAL_COPY_PROP(p, &properties_table_snapshot[i]); - Z_TRY_DELREF_P(p); + ZVAL_COPY_VALUE_PROP(p, &properties_table_snapshot[i]); zend_property_info *prop_info = ce->properties_info_table[i]; if (Z_ISREF_P(p) && prop_info && ZEND_TYPE_IS_SET(prop_info->type)) { From d0c9e36acffc6e8d121a4d5e9b997b365995aeed Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 21:26:16 +0200 Subject: [PATCH 45/56] Prevent making object lazy during its initialization --- .../reset_as_lazy_while_init_exception.phpt | 57 +++++++++++++++++++ Zend/zend_lazy_objects.c | 32 ++++++++--- 2 files changed, 80 insertions(+), 9 deletions(-) create mode 100644 Zend/tests/lazy_objects/reset_as_lazy_while_init_exception.phpt diff --git a/Zend/tests/lazy_objects/reset_as_lazy_while_init_exception.phpt b/Zend/tests/lazy_objects/reset_as_lazy_while_init_exception.phpt new file mode 100644 index 0000000000000..756bad70621da --- /dev/null +++ b/Zend/tests/lazy_objects/reset_as_lazy_while_init_exception.phpt @@ -0,0 +1,57 @@ +--TEST-- +Lazy objects: resetAsLazy*() on object being initialized +--FILE-- +resetAsLazyGhost($obj, function ($obj) use ($reflector) { + try { + $reflector->resetAsLazyGhost($obj, function () { }); + } catch (Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + try { + $reflector->resetAsLazyProxy($obj, function () { }); + } catch (Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + +}); +$reflector->initializeLazyObject($obj); + +printf("# Proxy:\n"); + +$obj = new C(); +$reflector->resetAsLazyProxy($obj, function ($obj) use ($reflector) { + try { + $reflector->resetAsLazyProxy($obj, function () { }); + } catch (Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + try { + $reflector->resetAsLazyGhost($obj, function () { }); + } catch (Error $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + return new C(); +}); +$reflector->initializeLazyObject($obj); + +?> +==DONE== +--EXPECT-- +# Ghost: +Error: Can not reset an object while it is being initialized +Error: Can not reset an object while it is being initialized +# Proxy: +Error: Can not reset an object while it is being initialized +Error: Can not reset an object while it is being initialized +==DONE== diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 75ba3de07efe0..861f8e2f8168a 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -112,6 +112,11 @@ static zend_lazy_object_info* zend_lazy_object_get_info(zend_object *obj) return info; } +static bool zend_lazy_object_has_stale_info(zend_object *obj) +{ + return zend_hash_index_find_ptr(&EG(lazy_objects_store).infos, obj->handle); +} + zval* zend_lazy_object_get_initializer_zv(zend_object *obj) { ZEND_ASSERT(!zend_lazy_object_initialized(obj)); @@ -249,16 +254,23 @@ ZEND_API zend_object *zend_object_make_lazy(zend_object *obj, ZEND_ASSERT(zend_object_is_lazy_proxy(obj) && zend_lazy_object_initialized(obj)); OBJ_EXTRA_FLAGS(obj) &= ~(IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY); zend_lazy_object_del_info(obj); - } else if (!(flags & ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR) + } else { + if (zend_lazy_object_has_stale_info(obj)) { + zend_throw_error(NULL, "Can not reset an object while it is being initialized"); + return NULL; + } + + if (!(flags & ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR) && !(OBJ_FLAGS(obj) & IS_OBJ_DESTRUCTOR_CALLED)) { - if (obj->handlers->dtor_obj != zend_objects_destroy_object - || obj->ce->destructor) { - GC_ADD_FLAGS(obj, IS_OBJ_DESTRUCTOR_CALLED); - GC_ADDREF(obj); - obj->handlers->dtor_obj(obj); - GC_DELREF(obj); - if (EG(exception)) { - return NULL; + if (obj->handlers->dtor_obj != zend_objects_destroy_object + || obj->ce->destructor) { + GC_ADD_FLAGS(obj, IS_OBJ_DESTRUCTOR_CALLED); + GC_ADDREF(obj); + obj->handlers->dtor_obj(obj); + GC_DELREF(obj); + if (EG(exception)) { + return NULL; + } } } } @@ -571,6 +583,8 @@ 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); return obj; From 9248c394ec4fffc33594070f8bbd136132327668 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 21:30:26 +0200 Subject: [PATCH 46/56] Improve error message --- .../initializer_must_return_the_right_type.phpt | 2 +- Zend/zend_lazy_objects.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Zend/tests/lazy_objects/initializer_must_return_the_right_type.phpt b/Zend/tests/lazy_objects/initializer_must_return_the_right_type.phpt index dd68a88406eeb..7f796684e1bd8 100644 --- a/Zend/tests/lazy_objects/initializer_must_return_the_right_type.phpt +++ b/Zend/tests/lazy_objects/initializer_must_return_the_right_type.phpt @@ -152,7 +152,7 @@ string(11) "initializer" TypeError: The real instance class DateTime is not compatible with the proxy class C. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor or __clone methods. ## C vs NULL string(11) "initializer" -TypeError: The real instance class null is not compatible with the proxy class C. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor or __clone methods. +TypeError: Lazy proxy factory must return an instance of a class compatible with C, null returned ## C vs D string(11) "initializer" TypeError: The real instance class D is not compatible with the proxy class C. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor or __clone methods. diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 861f8e2f8168a..e0b300b14667c 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -449,6 +449,16 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj) return NULL; } + if (UNEXPECTED(Z_TYPE(retval) != IS_OBJECT)) { + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY; + zend_type_error("Lazy proxy factory must return an instance of a class compatible with %s, %s returned", + ZSTR_VAL(obj->ce->name), + zend_zval_value_name(&retval)); + zval_ptr_dtor(&retval); + return NULL; + + } + if (UNEXPECTED(Z_TYPE(retval) != IS_OBJECT || !zend_lazy_object_compatible(Z_OBJ(retval), obj))) { OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY; zend_type_error("The real instance class %s is not compatible with the proxy class %s. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor or __clone methods.", From 4a0eb5fce3e37f25be6fe261082c1ce86a974bfc Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 22:00:25 +0200 Subject: [PATCH 47/56] Fix build --- ext/ffi/ffi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index f5fe23f955398..6d9216b6f7f3f 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -246,7 +246,7 @@ static zend_always_inline void zend_ffi_object_init(zend_object *object, zend_cl { GC_SET_REFCOUNT(object, 1); GC_TYPE_INFO(object) = GC_OBJECT | (IS_OBJ_DESTRUCTOR_CALLED << GC_FLAGS_SHIFT); - object->flags = 0; + object->extra_flags = 0; object->ce = ce; object->handlers = ce->default_object_handlers; object->properties = NULL; From b960778695302b04527de266564cf18439526f41 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 22:05:45 +0200 Subject: [PATCH 48/56] Rename constants --- Zend/zend_lazy_objects.c | 6 +++--- Zend/zend_lazy_objects.h | 4 ++-- ext/reflection/php_reflection.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index e0b300b14667c..cda1410c1c264 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -205,9 +205,9 @@ ZEND_API zend_object *zend_object_make_lazy(zend_object *obj, zend_class_entry *reflection_ce, zval *initializer_zv, zend_fcall_info_cache *initializer_fcc, zend_lazy_object_flags_t flags) { - ZEND_ASSERT(!(flags & ~(ZEND_LAZY_OBJECT_USER_FLAGS|ZEND_LAZY_OBJECT_STRATEGY_FLAGS))); - ZEND_ASSERT((flags & ZEND_LAZY_OBJECT_STRATEGY_FLAGS) == ZEND_LAZY_OBJECT_STRATEGY_GHOST - || (flags & ZEND_LAZY_OBJECT_STRATEGY_FLAGS) == ZEND_LAZY_OBJECT_STRATEGY_PROXY); + ZEND_ASSERT(!(flags & ~(ZEND_LAZY_OBJECT_USER_MASK|ZEND_LAZY_OBJECT_STRATEGY_MASK))); + ZEND_ASSERT((flags & ZEND_LAZY_OBJECT_STRATEGY_MASK) == ZEND_LAZY_OBJECT_STRATEGY_GHOST + || (flags & ZEND_LAZY_OBJECT_STRATEGY_MASK) == ZEND_LAZY_OBJECT_STRATEGY_PROXY); ZEND_ASSERT(!obj || (!zend_object_is_lazy(obj) || zend_lazy_object_initialized(obj))); ZEND_ASSERT(!obj || instanceof_function(obj->ce, reflection_ce)); diff --git a/Zend/zend_lazy_objects.h b/Zend/zend_lazy_objects.h index a10e2205673a5..ecfd0293a57f0 100644 --- a/Zend/zend_lazy_objects.h +++ b/Zend/zend_lazy_objects.h @@ -36,12 +36,12 @@ /* Do not call destructor when making existing object lazy */ #define ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR (1<<4) -#define ZEND_LAZY_OBJECT_USER_FLAGS ( \ +#define ZEND_LAZY_OBJECT_USER_MASK ( \ ZEND_LAZY_OBJECT_SKIP_INITIALIZATION_ON_SERIALIZE | \ ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR \ ) -#define ZEND_LAZY_OBJECT_STRATEGY_FLAGS ( \ +#define ZEND_LAZY_OBJECT_STRATEGY_MASK ( \ ZEND_LAZY_OBJECT_STRATEGY_PROXY | \ ZEND_LAZY_OBJECT_STRATEGY_GHOST \ ) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index b5c62e006639a..972f119b51dd5 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -5222,7 +5222,7 @@ void reflection_class_new_lazy(INTERNAL_FUNCTION_PARAMETERS, obj = NULL; } - zend_long accepted_flags = ZEND_LAZY_OBJECT_USER_FLAGS; + zend_long accepted_flags = ZEND_LAZY_OBJECT_USER_MASK; if (options & ~accepted_flags) { uint32_t arg_num = 2 + is_reset; zend_argument_error(reflection_exception_ptr, arg_num, From 174fe00bd3158fbdf3acd6884b5abf82278012a4 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 20 Aug 2024 22:15:56 +0200 Subject: [PATCH 49/56] CS --- ext/reflection/php_reflection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 972f119b51dd5..5c43c6004807f 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -5230,7 +5230,7 @@ void reflection_class_new_lazy(INTERNAL_FUNCTION_PARAMETERS, RETURN_THROWS(); } - if (!is_reset && options & ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR) { + if (!is_reset && (options & ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR)) { zend_argument_error(reflection_exception_ptr, 2, "does not accept ReflectionClass::SKIP_DESTRUCTOR"); RETURN_THROWS(); From 7f2190e4ef759b48580c74adc819d8be65957f05 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Wed, 21 Aug 2024 12:16:05 +0200 Subject: [PATCH 50/56] Generated file --- Zend/zend_vm_execute.h | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index edcab7848cc10..90e50d7362de8 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -5172,10 +5172,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CONST_H } else { ZVAL_EMPTY_ARRAY(result); } - } else if (Z_OBJ_P(expr)->properties == NULL - && Z_OBJ_HT_P(expr)->get_properties_for == NULL - && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties - && (!zend_object_is_lazy_proxy(Z_OBJ_P(expr)) || !zend_lazy_object_initialized(Z_OBJ_P(expr)))) { + } else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(expr)) { /* Optimized version without rebuilding properties HashTable */ ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); } else { @@ -20046,10 +20043,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPC } else { ZVAL_EMPTY_ARRAY(result); } - } else if (Z_OBJ_P(expr)->properties == NULL - && Z_OBJ_HT_P(expr)->get_properties_for == NULL - && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties - && (!zend_object_is_lazy_proxy(Z_OBJ_P(expr)) || !zend_lazy_object_initialized(Z_OBJ_P(expr)))) { + } else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(expr)) { /* Optimized version without rebuilding properties HashTable */ ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); } else { @@ -22700,10 +22694,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPC } else { ZVAL_EMPTY_ARRAY(result); } - } else if (Z_OBJ_P(expr)->properties == NULL - && Z_OBJ_HT_P(expr)->get_properties_for == NULL - && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties - && (!zend_object_is_lazy_proxy(Z_OBJ_P(expr)) || !zend_lazy_object_initialized(Z_OBJ_P(expr)))) { + } else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(expr)) { /* Optimized version without rebuilding properties HashTable */ ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); } else { @@ -40746,10 +40737,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCO } else { ZVAL_EMPTY_ARRAY(result); } - } else if (Z_OBJ_P(expr)->properties == NULL - && Z_OBJ_HT_P(expr)->get_properties_for == NULL - && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties - && (!zend_object_is_lazy_proxy(Z_OBJ_P(expr)) || !zend_lazy_object_initialized(Z_OBJ_P(expr)))) { + } else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(expr)) { /* Optimized version without rebuilding properties HashTable */ ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); } else { From 5864de35926b0b3bd02d564bc491f0a267672f56 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Wed, 21 Aug 2024 14:34:06 +0200 Subject: [PATCH 51/56] Do not inline slow path --- Zend/zend_lazy_objects.c | 16 ++++++++++++++++ Zend/zend_lazy_objects.h | 1 + Zend/zend_object_handlers.h | 7 +------ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index cda1410c1c264..227f47ef28f1b 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -617,6 +617,22 @@ void zend_lazy_object_realize(zend_object *obj) OBJ_EXTRA_FLAGS(obj) &= ~(IS_OBJ_LAZY_UNINITIALIZED | IS_OBJ_LAZY_PROXY); } +ZEND_API HashTable *zend_lazy_object_get_properties(zend_object *object) +{ + ZEND_ASSERT(zend_object_is_lazy(object)); + + zend_object *tmp = zend_lazy_object_init(object); + if (UNEXPECTED(!tmp)) { + ZEND_ASSERT(!object->properties || object->properties == &zend_empty_array); + return object->properties = (zend_array*) &zend_empty_array; + } + + object = tmp; + ZEND_ASSERT(!zend_lazy_object_must_init(object)); + + return zend_std_get_properties_ex(object); +} + /* Initialize object and clone it. For proxies, we clone both the proxy and its * real instance, and we don't call __clone() on the proxy. */ zend_object *zend_lazy_object_clone(zend_object *old_obj) diff --git a/Zend/zend_lazy_objects.h b/Zend/zend_lazy_objects.h index ecfd0293a57f0..addb07173c3f4 100644 --- a/Zend/zend_lazy_objects.h +++ b/Zend/zend_lazy_objects.h @@ -69,6 +69,7 @@ zval* zend_lazy_object_get_initializer_zv(zend_object *obj); zend_object *zend_lazy_object_get_instance(zend_object *obj); zend_lazy_object_flags_t zend_lazy_object_get_flags(zend_object *obj); void zend_lazy_object_del_info(zend_object *obj); +ZEND_API HashTable *zend_lazy_object_get_properties(zend_object *object); zend_object *zend_lazy_object_clone(zend_object *old_obj); HashTable *zend_lazy_object_debug_info(zend_object *object, int *is_temp); HashTable *zend_lazy_object_get_gc(zend_object *zobj, zval **table, int *n); diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index add97f47c0ef1..f36eb765c24a5 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -276,12 +276,7 @@ ZEND_API HashTable *rebuild_object_properties_internal(zend_object *zobj); static zend_always_inline HashTable *zend_std_get_properties_ex(zend_object *object) { if (UNEXPECTED(zend_lazy_object_must_init(object))) { - zend_object *tmp = zend_lazy_object_init(object); - if (UNEXPECTED(!tmp)) { - ZEND_ASSERT(!object->properties || object->properties == &zend_empty_array); - return object->properties = (zend_array*) &zend_empty_array; - } - object = tmp; + return zend_lazy_object_get_properties(object); } if (!object->properties) { return rebuild_object_properties_internal(object); From d1a10acab724824f78c41828962b37e88f996876 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Wed, 21 Aug 2024 14:36:00 +0200 Subject: [PATCH 52/56] Ensure separation --- .../lazy_objects/init_exception_001.phpt | 29 ++ Zend/zend_vm_def.h | 12 +- Zend/zend_vm_execute.h | 432 ++++++++++++++++-- 3 files changed, 436 insertions(+), 37 deletions(-) create mode 100644 Zend/tests/lazy_objects/init_exception_001.phpt diff --git a/Zend/tests/lazy_objects/init_exception_001.phpt b/Zend/tests/lazy_objects/init_exception_001.phpt new file mode 100644 index 0000000000000..81469b9992d6b --- /dev/null +++ b/Zend/tests/lazy_objects/init_exception_001.phpt @@ -0,0 +1,29 @@ +--TEST-- +Lazy objects: init exception 001 +--FILE-- +newLazyGhost(function ($obj) use ($i) { + if ($i === 1) { + throw new \Exception(); + } + }); + $obj->c = 1; +} + +?> +--EXPECTF-- +Fatal error: Uncaught Exception in %s:%d +Stack trace: +#0 %s(%d): {closure:%s:%d}(Object(C)) +#1 {main} + thrown in %s on line %d diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 49bdd99189838..b46952a81718b 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2481,6 +2481,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + ZEND_VM_C_GOTO(free_and_exit_assign_obj); + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -2519,7 +2529,7 @@ ZEND_VM_C_LABEL(fast_assign_obj): Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 90e50d7362de8..6738674667e74 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -23975,6 +23975,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -24013,7 +24023,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -24119,6 +24129,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -24157,7 +24177,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -24263,6 +24283,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -24301,7 +24331,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -24407,6 +24437,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -24445,7 +24485,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -26937,6 +26977,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -26975,7 +27025,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -27081,6 +27131,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -27119,7 +27179,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -27225,6 +27285,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -27263,7 +27333,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -27369,6 +27439,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -27407,7 +27487,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -31261,6 +31341,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -31299,7 +31389,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -31405,6 +31495,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -31443,7 +31543,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -31549,6 +31649,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -31587,7 +31697,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -31693,6 +31803,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -31731,7 +31851,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -33979,6 +34099,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -34017,7 +34147,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -34123,6 +34253,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -34161,7 +34301,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -34267,6 +34407,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -34305,7 +34455,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -34411,6 +34561,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -34449,7 +34609,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -36118,6 +36278,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -36156,7 +36326,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -36262,6 +36432,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -36300,7 +36480,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -36406,6 +36586,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -36444,7 +36634,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -36550,6 +36740,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -36588,7 +36788,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -38735,6 +38935,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -38773,7 +38983,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -38879,6 +39089,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -38917,7 +39137,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -39023,6 +39243,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -39061,7 +39291,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -39167,6 +39397,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -39205,7 +39445,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -43089,6 +43329,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -43127,7 +43377,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -43233,6 +43483,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -43271,7 +43531,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -43377,6 +43637,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -43415,7 +43685,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -43521,6 +43791,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -43559,7 +43839,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -47012,6 +47292,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -47050,7 +47340,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -47156,6 +47446,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -47194,7 +47494,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -47300,6 +47600,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -47338,7 +47648,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -47444,6 +47754,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -47482,7 +47802,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -52482,6 +52802,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -52520,7 +52850,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -52626,6 +52956,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -52664,7 +53004,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -52770,6 +53110,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -52808,7 +53158,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -52914,6 +53264,16 @@ 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); + if (!zobj) { + value = &EG(uninitialized_zval); + goto free_and_exit_assign_obj; + } + } + if (!zobj->ce->__set && (zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + rebuild_object_properties_internal(zobj); + } if (EXPECTED(zobj->properties != NULL)) { if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { @@ -52952,7 +53312,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ Z_TRY_ADDREF_P(value); } } - zend_hash_add_new(zend_std_get_properties_ex(zobj), name, value); + zend_hash_add_new(zobj->properties, name, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } From 3e5c95c6b9522646b7afd5cb76355ffc0aabd823 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Wed, 21 Aug 2024 14:44:18 +0200 Subject: [PATCH 53/56] Simplify --- .../json_encode_dynamic_props.phpt | 49 +++++++++++++++ .../lazy_objects/serialize_dynamic_props.phpt | 48 +++++++++++++++ .../serialize_failed_lazy_object.phpt | 50 ++++++++++++++++ ...ed_lazy_object_skip_init_on_serialize.phpt | 60 +++++++++++++++++++ ext/json/json_encoder.c | 11 +--- ext/standard/var.c | 13 +--- 6 files changed, 211 insertions(+), 20 deletions(-) create mode 100644 Zend/tests/lazy_objects/json_encode_dynamic_props.phpt create mode 100644 Zend/tests/lazy_objects/serialize_dynamic_props.phpt create mode 100644 Zend/tests/lazy_objects/serialize_failed_lazy_object.phpt create mode 100644 Zend/tests/lazy_objects/serialize_failed_lazy_object_skip_init_on_serialize.phpt diff --git a/Zend/tests/lazy_objects/json_encode_dynamic_props.phpt b/Zend/tests/lazy_objects/json_encode_dynamic_props.phpt new file mode 100644 index 0000000000000..19b4e7c86005a --- /dev/null +++ b/Zend/tests/lazy_objects/json_encode_dynamic_props.phpt @@ -0,0 +1,49 @@ +--TEST-- +Lazy objects: json_encode with dynamic props on initialized object +--FILE-- +newLazyGhost(function ($obj) { + $obj->dyn = 1; +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + $c = new C(); + $c->dyn = 1; + return $c; +}); + +test('Proxy', $obj); + +--EXPECTF-- +# Ghost +object(stdClass)#%d (2) { + ["a"]=> + int(1) + ["dyn"]=> + int(1) +} +# Proxy +object(stdClass)#%d (2) { + ["a"]=> + int(1) + ["dyn"]=> + int(1) +} diff --git a/Zend/tests/lazy_objects/serialize_dynamic_props.phpt b/Zend/tests/lazy_objects/serialize_dynamic_props.phpt new file mode 100644 index 0000000000000..b2465ded4f4b5 --- /dev/null +++ b/Zend/tests/lazy_objects/serialize_dynamic_props.phpt @@ -0,0 +1,48 @@ +--TEST-- +Lazy objects: serialize() with dynamic props on initialized object +--FILE-- +newLazyGhost(function ($obj) { + $obj->dyn = 1; +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + $c = new C(); + $c->dyn = 1; + return $c; +}); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +object(C)#%d (1) { + ["a"]=> + uninitialized(int) + ["dyn"]=> + int(1) +} +# Proxy +object(C)#%d (1) { + ["a"]=> + uninitialized(int) + ["dyn"]=> + int(1) +} diff --git a/Zend/tests/lazy_objects/serialize_failed_lazy_object.phpt b/Zend/tests/lazy_objects/serialize_failed_lazy_object.phpt new file mode 100644 index 0000000000000..7fdf8fb771652 --- /dev/null +++ b/Zend/tests/lazy_objects/serialize_failed_lazy_object.phpt @@ -0,0 +1,50 @@ +--TEST-- +Lazy objects: serialize() a lazy object that previously failed to initialize +--FILE-- +initializeLazyObject($obj); + } catch (Exception $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + + try { + var_dump(unserialize(serialize($obj))); + } catch (Exception $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } +} + +$obj = $reflector->newLazyGhost(function ($obj) { + throw new \Exception('Initializer'); +}); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + throw new \Exception('Initializer'); +}); + +test('Proxy', $obj); + +?> +--EXPECT-- +# Ghost +Exception: Initializer +Exception: Initializer +# Proxy +Exception: Initializer +Exception: Initializer diff --git a/Zend/tests/lazy_objects/serialize_failed_lazy_object_skip_init_on_serialize.phpt b/Zend/tests/lazy_objects/serialize_failed_lazy_object_skip_init_on_serialize.phpt new file mode 100644 index 0000000000000..4fbda267d52a4 --- /dev/null +++ b/Zend/tests/lazy_objects/serialize_failed_lazy_object_skip_init_on_serialize.phpt @@ -0,0 +1,60 @@ +--TEST-- +Lazy objects: serialize() a lazy object that previously failed to initialize, with SKIP_INITIALIZATION_ON_SERIALIZE +--FILE-- +initializeLazyObject($obj); + } catch (Exception $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } + + try { + var_dump(unserialize(serialize($obj))); + } catch (Exception $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } +} + +$obj = $reflector->newLazyGhost(function ($obj) { + throw new \Exception('Initializer'); +}, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); + +test('Ghost', $obj); + +$obj = $reflector->newLazyProxy(function () { + throw new \Exception('Initializer'); +}, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE); + +test('Proxy', $obj); + +?> +--EXPECTF-- +# Ghost +Exception: Initializer +object(C)#%d (1) { + ["a"]=> + uninitialized(int) + ["b"]=> + NULL +} +# Proxy +Exception: Initializer +object(C)#%d (1) { + ["a"]=> + uninitialized(int) + ["b"]=> + NULL +} diff --git a/ext/json/json_encoder.c b/ext/json/json_encoder.c index 6d28ab033336d..de3106601b9c5 100644 --- a/ext/json/json_encoder.c +++ b/ext/json/json_encoder.c @@ -125,17 +125,10 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, } else if (Z_OBJ_P(val)->properties == NULL && Z_OBJ_HT_P(val)->get_properties_for == NULL && Z_OBJ_HT_P(val)->get_properties == zend_std_get_properties - && Z_OBJ_P(val)->ce->num_hooked_props == 0) { + && Z_OBJ_P(val)->ce->num_hooked_props == 0 + && !zend_object_is_lazy(Z_OBJ_P(val))) { /* Optimized version without rebuilding properties HashTable */ zend_object *obj = Z_OBJ_P(val); - - if (zend_lazy_object_must_init(Z_OBJ_P(val))) { - obj = zend_lazy_object_init(Z_OBJ_P(val)); - if (!obj) { - return FAILURE; - } - } - zend_class_entry *ce = obj->ce; zend_property_info *prop_info; zval *prop; diff --git a/ext/standard/var.c b/ext/standard/var.c index 14af705b6331f..0d08a0a338309 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -1224,19 +1224,10 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_ if (Z_OBJ_P(struc)->properties == NULL && Z_OBJ_HT_P(struc)->get_properties_for == NULL - && Z_OBJ_HT_P(struc)->get_properties == zend_std_get_properties) { + && Z_OBJ_HT_P(struc)->get_properties == zend_std_get_properties + && !zend_object_is_lazy(Z_OBJ_P(struc))) { /* Optimized version without rebulding properties HashTable */ zend_object *obj = Z_OBJ_P(struc); - - if (zend_lazy_object_must_init(Z_OBJ_P(struc)) - && zend_lazy_object_initialize_on_serialize(Z_OBJ_P(struc))) { - obj = zend_lazy_object_init(Z_OBJ_P(struc)); - if (!obj) { - ZEND_ASSERT(EG(exception)); - return; - } - } - zend_class_entry *ce = obj->ce; zend_property_info *prop_info; zval *prop; From c332fa5e8dc86c71316be1358470abad6fcfaa3c Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Wed, 28 Aug 2024 17:42:21 +0200 Subject: [PATCH 54/56] Add assertion --- Zend/zend_API.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Zend/zend_API.c b/Zend/zend_API.c index aa6e15b633334..b4f13bedecc56 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1803,6 +1803,7 @@ static zend_always_inline zend_result _object_and_properties_init(zval *arg, zen } else if (class_type->ce_flags & ZEND_ACC_ENUM) { zend_throw_error(NULL, "Cannot instantiate enum %s", ZSTR_VAL(class_type->name)); } else { + ZEND_ASSERT(class_type->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)); zend_throw_error(NULL, "Cannot instantiate abstract class %s", ZSTR_VAL(class_type->name)); } ZVAL_NULL(arg); From 9114a71e2ac4d76bd23584da7122144179d625a9 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Wed, 28 Aug 2024 17:42:30 +0200 Subject: [PATCH 55/56] Prevent compiler warning --- Zend/zend_lazy_objects.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 227f47ef28f1b..357150bc63876 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -234,6 +234,7 @@ ZEND_API zend_object *zend_object_make_lazy(zend_object *obj, /* Call object_init_ex() for the generated exception */ zend_result result = object_init_ex(&zobj, reflection_ce); ZEND_ASSERT(result == FAILURE && EG(exception)); + (void)result; return NULL; } From 3b3a2008325a5936bd03bd5616cb827911e927e9 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Wed, 28 Aug 2024 17:42:39 +0200 Subject: [PATCH 56/56] Simplify --- ext/reflection/php_reflection.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 5c43c6004807f..531db004b3ba6 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -5222,8 +5222,7 @@ void reflection_class_new_lazy(INTERNAL_FUNCTION_PARAMETERS, obj = NULL; } - zend_long accepted_flags = ZEND_LAZY_OBJECT_USER_MASK; - if (options & ~accepted_flags) { + if (options & ~ZEND_LAZY_OBJECT_USER_MASK) { uint32_t arg_num = 2 + is_reset; zend_argument_error(reflection_exception_ptr, arg_num, "contains invalid flags");