Commit 523a75eea92 for php.net

commit 523a75eea9228ddd631eb64b8055456a68cf4c8c
Author: Weilin Du <weilindu@php.net>
Date:   Tue Aug 4 00:08:45 2026 +0800

    Zend: factor out guarded lazy-proxy forwarding in object handlers (#22983)

    Refactor out duplicate logic to make the code looks more sensible.

diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index 313113d7dc2..754f603100c 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -669,6 +669,23 @@ ZEND_API uint32_t *zend_get_recursion_guard(zend_object *zobj)
 	return &Z_GUARD_P(zv);
 }

+static zend_always_inline zend_object *zend_lazy_proxy_get_guarded_instance(
+		zend_object *zobj, zend_string *name, uint32_t guard_type)
+{
+	if (UNEXPECTED(zend_object_is_lazy_proxy(zobj)
+			&& zend_lazy_object_initialized(zobj))) {
+		zend_object *instance = zend_lazy_object_get_instance(zobj);
+		if (instance->ce->ce_flags & ZEND_ACC_USE_GUARDS) {
+			uint32_t *instance_guard = zend_get_property_guard(instance, name);
+			if ((*instance_guard) & guard_type) {
+				return instance;
+			}
+		}
+	}
+
+	return NULL;
+}
+
 ZEND_COLD static void zend_typed_property_uninitialized_access(const zend_property_info *prop_info, zend_string *name)
 {
 	zend_throw_error(NULL, "Typed property %s::$%s must not be accessed before initialization",
@@ -896,21 +913,16 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int
 	 * guard is already set for this property, we are inside a recursive
 	 * call from the real instance's __get/__isset. Forward directly to
 	 * the real instance to avoid double invocation. (GH-21478) */
-	if (UNEXPECTED(zend_object_is_lazy_proxy(zobj)
-			&& zend_lazy_object_initialized(zobj))) {
-		zend_object *instance = zend_lazy_object_get_instance(zobj);
-		if (instance->ce->ce_flags & ZEND_ACC_USE_GUARDS) {
-			uint32_t *instance_guard = zend_get_property_guard(instance, name);
-			uint32_t guard_type = ((type == BP_VAR_IS) && zobj->ce->__isset)
-				? IN_ISSET : IN_GET;
-			if ((*instance_guard) & guard_type) {
-				retval = zend_std_read_property(instance, name, type, cache_slot, rv);
-				if (retval == &EG(uninitialized_zval)) {
-					ZVAL_NULL(rv);
-					retval = rv;
-				}
-				return retval;
+	{
+		zend_object *instance = zend_lazy_proxy_get_guarded_instance(zobj, name,
+			((type == BP_VAR_IS) && zobj->ce->__isset) ? IN_ISSET : IN_GET);
+		if (instance) {
+			retval = zend_std_read_property(instance, name, type, cache_slot, rv);
+			if (retval == &EG(uninitialized_zval)) {
+				ZVAL_NULL(rv);
+				retval = rv;
 			}
+			return retval;
 		}
 	}

@@ -1262,14 +1274,10 @@ found:;
 	/* For initialized lazy proxies: if the real instance's __set guard
 	 * is already set, we are inside a recursive call from the real
 	 * instance's __set. Forward directly to avoid double invocation. */
-	if (UNEXPECTED(zend_object_is_lazy_proxy(zobj)
-			&& zend_lazy_object_initialized(zobj))) {
-		zend_object *instance = zend_lazy_object_get_instance(zobj);
-		if (instance->ce->ce_flags & ZEND_ACC_USE_GUARDS) {
-			uint32_t *instance_guard = zend_get_property_guard(instance, name);
-			if ((*instance_guard) & IN_SET) {
-				return zend_std_write_property(instance, name, value, cache_slot);
-			}
+	{
+		zend_object *instance = zend_lazy_proxy_get_guarded_instance(zobj, name, IN_SET);
+		if (instance) {
+			return zend_std_write_property(instance, name, value, cache_slot);
 		}
 	}

@@ -1670,15 +1678,11 @@ ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void
 	/* For initialized lazy proxies: if the real instance's __unset guard
 	 * is already set, we are inside a recursive call from the real
 	 * instance's __unset. Forward directly to avoid double invocation. */
-	if (UNEXPECTED(zend_object_is_lazy_proxy(zobj)
-			&& zend_lazy_object_initialized(zobj))) {
-		zend_object *instance = zend_lazy_object_get_instance(zobj);
-		if (instance->ce->ce_flags & ZEND_ACC_USE_GUARDS) {
-			uint32_t *instance_guard = zend_get_property_guard(instance, name);
-			if ((*instance_guard) & IN_UNSET) {
-				zend_std_unset_property(instance, name, cache_slot);
-				return;
-			}
+	{
+		zend_object *instance = zend_lazy_proxy_get_guarded_instance(zobj, name, IN_UNSET);
+		if (instance) {
+			zend_std_unset_property(instance, name, cache_slot);
+			return;
 		}
 	}

@@ -2498,14 +2502,10 @@ ZEND_API int zend_std_has_property(zend_object *zobj, zend_string *name, int has
 	/* For initialized lazy proxies: if the real instance's __isset guard
 	 * is already set, we are inside a recursive call from the real
 	 * instance's __isset. Forward directly to avoid double invocation. */
-	if (UNEXPECTED(zend_object_is_lazy_proxy(zobj)
-			&& zend_lazy_object_initialized(zobj))) {
-		zend_object *instance = zend_lazy_object_get_instance(zobj);
-		if (instance->ce->ce_flags & ZEND_ACC_USE_GUARDS) {
-			uint32_t *instance_guard = zend_get_property_guard(instance, name);
-			if ((*instance_guard) & IN_ISSET) {
-				return zend_std_has_property(instance, name, has_set_exists, cache_slot);
-			}
+	{
+		zend_object *instance = zend_lazy_proxy_get_guarded_instance(zobj, name, IN_ISSET);
+		if (instance) {
+			return zend_std_has_property(instance, name, has_set_exists, cache_slot);
 		}
 	}