From a2327439769bf6d992c06cc4d5f260190a48d606 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Thu, 10 Oct 2024 16:22:24 +0200 Subject: [PATCH 1/3] Add ReflectionProperty::isUninitializedLazy() --- Zend/tests/lazy_objects/is_uninit_lazy.phpt | 101 ++++++++++++++++++++ ext/reflection/php_reflection.c | 25 +++++ ext/reflection/php_reflection.stub.php | 2 + ext/reflection/php_reflection_arginfo.h | 6 +- 4 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/lazy_objects/is_uninit_lazy.phpt diff --git a/Zend/tests/lazy_objects/is_uninit_lazy.phpt b/Zend/tests/lazy_objects/is_uninit_lazy.phpt new file mode 100644 index 0000000000000..80be6afba7029 --- /dev/null +++ b/Zend/tests/lazy_objects/is_uninit_lazy.phpt @@ -0,0 +1,101 @@ +--TEST-- +Lazy Objects: ReflectionProperty::isUninitializedLazy() +--FILE-- +dynamic = 1; + $pr = new ReflectionProperty($tmp, $name); + } else { + $pr = $reflector->getProperty($name); + } + printf("%s: %d\n", $name, $pr->isUninitializedLazy($obj)); + } +} + +$reflector = new ReflectionClass(C::class); + +print "# Ghost\n"; + +$obj = $reflector->newLazyGhost(function () { }); + +testProps($reflector, $obj); + +$pr = $reflector->getProperty('typed'); +$pr->skipLazyInitialization($obj); +printf("typed (skipped): %d\n", $pr->isUninitializedLazy($obj)); + +print "# Initialized Ghost\n"; + +$reflector->initializeLazyObject($obj); + +testProps($reflector, $obj); + +print "# Proxy\n"; + +$obj = $reflector->newLazyProxy(function () { + return new C(); +}); + +testProps($reflector, $obj); + +$pr = $reflector->getProperty('typed'); +$pr->skipLazyInitialization($obj); +printf("typed (skipped prop): %d\n", $pr->isUninitializedLazy($obj)); + +print "# Initialized Proxy\n"; + +$reflector->initializeLazyObject($obj); + +testProps($reflector, $obj); + +print "# Internal\n"; + +$obj = (new DateTime())->diff(new DateTime()); +$reflector = new ReflectionClass(DateInterval::class); +$pr = new ReflectionProperty($obj, 'y'); +printf("y: %d\n", $pr->isUninitializedLazy($obj)); + +?> +--EXPECT-- +# Ghost +staticProp: 0 +typed: 1 +untyped: 1 +virtual: 0 +dynamic: 0 +typed (skipped): 0 +# Initialized Ghost +staticProp: 0 +typed: 0 +untyped: 0 +virtual: 0 +dynamic: 0 +# Proxy +staticProp: 0 +typed: 1 +untyped: 1 +virtual: 0 +dynamic: 0 +typed (skipped prop): 0 +# Initialized Proxy +staticProp: 0 +typed: 0 +untyped: 0 +virtual: 0 +dynamic: 0 +# Internal +y: 0 diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 36edb6b527e15..010d7db7e4475 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6271,6 +6271,31 @@ ZEND_METHOD(ReflectionProperty, skipLazyInitialization) } } +/* {{{ Returns whether property is uninitialized and lazy */ +ZEND_METHOD(ReflectionProperty, isUninitializedLazy) +{ + reflection_object *intern; + property_reference *ref; + zend_object *object; + + GET_REFLECTION_OBJECT_PTR(ref); + + ZEND_PARSE_PARAMETERS_START(1, 1) { + Z_PARAM_OBJ_OF_CLASS(object, intern->ce) + } ZEND_PARSE_PARAMETERS_END(); + + if (!ref->prop || ref->prop->flags & (ZEND_ACC_STATIC | ZEND_ACC_VIRTUAL)) { + RETURN_FALSE; + } + + if (zend_object_is_lazy_proxy(object) + && zend_lazy_object_initialized(object)) { + object = zend_lazy_object_get_instance(object); + } + + RETURN_BOOL(Z_PROP_FLAG_P(OBJ_PROP(object, ref->prop->offset)) & IS_PROP_LAZY); +} + /* {{{ Returns true if property was initialized */ ZEND_METHOD(ReflectionProperty, isInitialized) { diff --git a/ext/reflection/php_reflection.stub.php b/ext/reflection/php_reflection.stub.php index 2b86559168012..ca0db3cca3147 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -502,6 +502,8 @@ public function setRawValueWithoutLazyInitialization(object $object, mixed $valu public function skipLazyInitialization(object $object): void {} + public function isUninitializedLazy(object $object): bool {} + /** @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 f55e96a7ed7ac..8598cd03327c4 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: 273777e0bc50a3d5059bb2db7b0a1e293b26e338 */ + * Stub hash: dd36f99fe094b6fe7f8b19590ed16735f3e5c719 */ 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) @@ -399,6 +399,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionProperty_skipLaz ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0) ZEND_END_ARG_INFO() +#define arginfo_class_ReflectionProperty_isUninitializedLazy arginfo_class_ReflectionClass_isUninitializedLazyObject + 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() @@ -843,6 +845,7 @@ ZEND_METHOD(ReflectionProperty, getRawValue); ZEND_METHOD(ReflectionProperty, setRawValue); ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization); ZEND_METHOD(ReflectionProperty, skipLazyInitialization); +ZEND_METHOD(ReflectionProperty, isUninitializedLazy); ZEND_METHOD(ReflectionProperty, isInitialized); ZEND_METHOD(ReflectionProperty, isPublic); ZEND_METHOD(ReflectionProperty, isPrivate); @@ -1140,6 +1143,7 @@ static const zend_function_entry class_ReflectionProperty_methods[] = { 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, isUninitializedLazy, arginfo_class_ReflectionProperty_isUninitializedLazy, 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) From 85f83c34d704223c642aae3b21b2aed16e21726a Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Wed, 23 Oct 2024 13:16:39 +0200 Subject: [PATCH 2/3] Rename to isLazy() --- .../lazy_objects/{is_uninit_lazy.phpt => isLazy.phpt} | 10 +++++----- ext/reflection/php_reflection.c | 3 +-- ext/reflection/php_reflection.stub.php | 2 +- ext/reflection/php_reflection_arginfo.h | 8 ++++---- 4 files changed, 11 insertions(+), 12 deletions(-) rename Zend/tests/lazy_objects/{is_uninit_lazy.phpt => isLazy.phpt} (84%) diff --git a/Zend/tests/lazy_objects/is_uninit_lazy.phpt b/Zend/tests/lazy_objects/isLazy.phpt similarity index 84% rename from Zend/tests/lazy_objects/is_uninit_lazy.phpt rename to Zend/tests/lazy_objects/isLazy.phpt index 80be6afba7029..9d944dc5d1eca 100644 --- a/Zend/tests/lazy_objects/is_uninit_lazy.phpt +++ b/Zend/tests/lazy_objects/isLazy.phpt @@ -1,5 +1,5 @@ --TEST-- -Lazy Objects: ReflectionProperty::isUninitializedLazy() +Lazy Objects: ReflectionProperty::isLazy() --FILE-- getProperty($name); } - printf("%s: %d\n", $name, $pr->isUninitializedLazy($obj)); + printf("%s: %d\n", $name, $pr->isLazy($obj)); } } @@ -36,7 +36,7 @@ testProps($reflector, $obj); $pr = $reflector->getProperty('typed'); $pr->skipLazyInitialization($obj); -printf("typed (skipped): %d\n", $pr->isUninitializedLazy($obj)); +printf("typed (skipped): %d\n", $pr->isLazy($obj)); print "# Initialized Ghost\n"; @@ -54,7 +54,7 @@ testProps($reflector, $obj); $pr = $reflector->getProperty('typed'); $pr->skipLazyInitialization($obj); -printf("typed (skipped prop): %d\n", $pr->isUninitializedLazy($obj)); +printf("typed (skipped prop): %d\n", $pr->isLazy($obj)); print "# Initialized Proxy\n"; @@ -67,7 +67,7 @@ print "# Internal\n"; $obj = (new DateTime())->diff(new DateTime()); $reflector = new ReflectionClass(DateInterval::class); $pr = new ReflectionProperty($obj, 'y'); -printf("y: %d\n", $pr->isUninitializedLazy($obj)); +printf("y: %d\n", $pr->isLazy($obj)); ?> --EXPECT-- diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 010d7db7e4475..0d78c73ee798d 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6271,8 +6271,7 @@ ZEND_METHOD(ReflectionProperty, skipLazyInitialization) } } -/* {{{ Returns whether property is uninitialized and lazy */ -ZEND_METHOD(ReflectionProperty, isUninitializedLazy) +ZEND_METHOD(ReflectionProperty, isLazy) { reflection_object *intern; property_reference *ref; diff --git a/ext/reflection/php_reflection.stub.php b/ext/reflection/php_reflection.stub.php index ca0db3cca3147..a4671cdf77386 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -502,7 +502,7 @@ public function setRawValueWithoutLazyInitialization(object $object, mixed $valu public function skipLazyInitialization(object $object): void {} - public function isUninitializedLazy(object $object): bool {} + public function isLazy(object $object): bool {} /** @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 8598cd03327c4..9f44ee949b08a 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: dd36f99fe094b6fe7f8b19590ed16735f3e5c719 */ + * Stub hash: 2620fb2d8fc950283bfc174372c72361b37e9d41 */ 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) @@ -399,7 +399,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionProperty_skipLaz ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0) ZEND_END_ARG_INFO() -#define arginfo_class_ReflectionProperty_isUninitializedLazy arginfo_class_ReflectionClass_isUninitializedLazyObject +#define arginfo_class_ReflectionProperty_isLazy arginfo_class_ReflectionClass_isUninitializedLazyObject 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") @@ -845,7 +845,7 @@ ZEND_METHOD(ReflectionProperty, getRawValue); ZEND_METHOD(ReflectionProperty, setRawValue); ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization); ZEND_METHOD(ReflectionProperty, skipLazyInitialization); -ZEND_METHOD(ReflectionProperty, isUninitializedLazy); +ZEND_METHOD(ReflectionProperty, isLazy); ZEND_METHOD(ReflectionProperty, isInitialized); ZEND_METHOD(ReflectionProperty, isPublic); ZEND_METHOD(ReflectionProperty, isPrivate); @@ -1143,7 +1143,7 @@ static const zend_function_entry class_ReflectionProperty_methods[] = { 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, isUninitializedLazy, arginfo_class_ReflectionProperty_isUninitializedLazy, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionProperty, isLazy, arginfo_class_ReflectionProperty_isLazy, 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) From 019d064fb9e903d72284eb85355c3f036a50f301 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Wed, 23 Oct 2024 14:48:54 +0200 Subject: [PATCH 3/3] Handle nested proxy --- Zend/tests/lazy_objects/isLazy.phpt | 39 +++++++++++++++++++++++++++++ ext/reflection/php_reflection.c | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/Zend/tests/lazy_objects/isLazy.phpt b/Zend/tests/lazy_objects/isLazy.phpt index 9d944dc5d1eca..691b42b708dbc 100644 --- a/Zend/tests/lazy_objects/isLazy.phpt +++ b/Zend/tests/lazy_objects/isLazy.phpt @@ -62,6 +62,33 @@ $reflector->initializeLazyObject($obj); testProps($reflector, $obj); +print "# Nested Proxy\n"; + +$nested = new C(); +$obj = $reflector->newLazyProxy(function () use ($nested) { + return $nested; +}); +$reflector->initializeLazyObject($obj); +$reflector->resetAsLazyProxy($nested, function () { + return new C(); +}); + +testProps($reflector, $obj); + +print "# Nested Proxy (nested initialized)\n"; + +$nested = new C(); +$obj = $reflector->newLazyProxy(function () use ($nested) { + return $nested; +}); +$reflector->initializeLazyObject($obj); +$reflector->resetAsLazyProxy($nested, function () { + return new C(); +}); +$reflector->initializeLazyObject($nested); + +testProps($reflector, $obj); + print "# Internal\n"; $obj = (new DateTime())->diff(new DateTime()); @@ -97,5 +124,17 @@ typed: 0 untyped: 0 virtual: 0 dynamic: 0 +# Nested Proxy +staticProp: 0 +typed: 1 +untyped: 1 +virtual: 0 +dynamic: 0 +# Nested Proxy (nested initialized) +staticProp: 0 +typed: 0 +untyped: 0 +virtual: 0 +dynamic: 0 # Internal y: 0 diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 0d78c73ee798d..e2a7bda46d304 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6287,7 +6287,7 @@ ZEND_METHOD(ReflectionProperty, isLazy) RETURN_FALSE; } - if (zend_object_is_lazy_proxy(object) + while (zend_object_is_lazy_proxy(object) && zend_lazy_object_initialized(object)) { object = zend_lazy_object_get_instance(object); }