Commit de36957ee82 for php.net

commit de36957ee82889ee81593e1cb2b069c7ffac7e79
Author: Daniel Scherzer <daniel.e.scherzer@gmail.com>
Date:   Wed Jul 8 20:10:11 2026 -0700

    Reflection: improve handling of dynamic properties in `_property_string()`

    For dynamic properties all of the representation details are known immediately,
    skip the checks for comments, flags, types, defaults, and hooks and use
    an early return.

diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c
index 2e585aff34c..f24d203439a 100644
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@ -992,96 +992,98 @@ static zval *property_get_default(const zend_property_info *prop_info) {
 /* {{{ _property_string */
 static void _property_string(smart_str *str, const zend_property_info *prop, const zend_string *prop_name, const char* indent)
 {
-	if (prop && prop->doc_comment) {
+	if (!prop) {
+		// Dynamic property, known to have no doc comment, flags, etc.
+		ZEND_ASSERT(prop_name && "Properties without info must have a name provided");
+		smart_str_append_printf(str, "%sProperty [ <dynamic> public $", indent);
+		smart_str_append(str, prop_name);
+		smart_str_appends(str, " ]\n");
+		return;
+	}
+	if (prop->doc_comment) {
 		smart_str_appends(str, indent);
 		smart_str_append(str, prop->doc_comment);
 		smart_str_appendc(str, '\n');
 	}
 	smart_str_append_printf(str, "%sProperty [ ", indent);
-	if (!prop) {
-		ZEND_ASSERT(prop_name && "Properties without info must have a name provided");
-		smart_str_appends(str, "<dynamic> public $");
-		smart_str_append(str, prop_name);
+	if (prop->flags & ZEND_ACC_ABSTRACT) {
+		smart_str_appends(str, "abstract ");
+	}
+	if (prop->flags & ZEND_ACC_FINAL) {
+		smart_str_appends(str, "final ");
+	}
+	/* These are mutually exclusive */
+	switch (prop->flags & ZEND_ACC_PPP_MASK) {
+		case ZEND_ACC_PUBLIC:
+			smart_str_appends(str, "public ");
+			break;
+		case ZEND_ACC_PRIVATE:
+			smart_str_appends(str, "private ");
+			break;
+		case ZEND_ACC_PROTECTED:
+			smart_str_appends(str, "protected ");
+			break;
+	}
+	switch (prop->flags & ZEND_ACC_PPP_SET_MASK) {
+		case ZEND_ACC_PRIVATE_SET:
+			smart_str_appends(str, "private(set) ");
+			break;
+		case ZEND_ACC_PROTECTED_SET:
+			smart_str_appends(str, "protected(set) ");
+			break;
+		case ZEND_ACC_PUBLIC_SET:
+			ZEND_UNREACHABLE();
+			break;
+	}
+	if (prop->flags & ZEND_ACC_STATIC) {
+		smart_str_appends(str, "static ");
+	}
+	if (prop->flags & ZEND_ACC_READONLY) {
+		smart_str_appends(str, "readonly ");
+	}
+	if (prop->flags & ZEND_ACC_VIRTUAL) {
+		smart_str_appends(str, "virtual ");
+	}
+	if (ZEND_TYPE_IS_SET(prop->type)) {
+		zend_string *type_str = zend_type_to_string(prop->type);
+		smart_str_append(str, type_str);
+		smart_str_appendc(str, ' ');
+		zend_string_release(type_str);
+	}
+	smart_str_appendc(str, '$');
+	if (!prop_name) {
+		const char *class_name;
+		const char *prop_name_cstr;
+		zend_unmangle_property_name(prop->name, &class_name, &prop_name_cstr);
+		smart_str_appends(str, prop_name_cstr);
 	} else {
-		if (prop->flags & ZEND_ACC_ABSTRACT) {
-			smart_str_appends(str, "abstract ");
-		}
-		if (prop->flags & ZEND_ACC_FINAL) {
-			smart_str_appends(str, "final ");
-		}
-		/* These are mutually exclusive */
-		switch (prop->flags & ZEND_ACC_PPP_MASK) {
-			case ZEND_ACC_PUBLIC:
-				smart_str_appends(str, "public ");
-				break;
-			case ZEND_ACC_PRIVATE:
-				smart_str_appends(str, "private ");
-				break;
-			case ZEND_ACC_PROTECTED:
-				smart_str_appends(str, "protected ");
-				break;
-		}
-		switch (prop->flags & ZEND_ACC_PPP_SET_MASK) {
-			case ZEND_ACC_PRIVATE_SET:
-				smart_str_appends(str, "private(set) ");
-				break;
-			case ZEND_ACC_PROTECTED_SET:
-				smart_str_appends(str, "protected(set) ");
-				break;
-			case ZEND_ACC_PUBLIC_SET:
-				ZEND_UNREACHABLE();
-				break;
-		}
-		if (prop->flags & ZEND_ACC_STATIC) {
-			smart_str_appends(str, "static ");
-		}
-		if (prop->flags & ZEND_ACC_READONLY) {
-			smart_str_appends(str, "readonly ");
-		}
-		if (prop->flags & ZEND_ACC_VIRTUAL) {
-			smart_str_appends(str, "virtual ");
-		}
-		if (ZEND_TYPE_IS_SET(prop->type)) {
-			zend_string *type_str = zend_type_to_string(prop->type);
-			smart_str_append(str, type_str);
-			smart_str_appendc(str, ' ');
-			zend_string_release(type_str);
-		}
-		smart_str_appendc(str, '$');
-		if (!prop_name) {
-			const char *class_name;
-			const char *prop_name_cstr;
-			zend_unmangle_property_name(prop->name, &class_name, &prop_name_cstr);
-			smart_str_appends(str, prop_name_cstr);
-		} else {
-			smart_str_append(str, prop_name);
-		}
+		smart_str_append(str, prop_name);
+	}

-		const zval *default_value = property_get_default(prop);
-		if (default_value && !Z_ISUNDEF_P(default_value)) {
-			smart_str_appends(str, " = ");
-			format_default_value(str, default_value);
-		}
-		if (prop->hooks != NULL) {
-			smart_str_appends(str, " {");
-			const zend_function *get_hooked = prop->hooks[ZEND_PROPERTY_HOOK_GET];
-			if (get_hooked != NULL) {
-				if (get_hooked->common.fn_flags & ZEND_ACC_FINAL) {
-					smart_str_appends(str, " final get;");
-				} else {
-					smart_str_appends(str, " get;");
-				}
+	const zval *default_value = property_get_default(prop);
+	if (default_value && !Z_ISUNDEF_P(default_value)) {
+		smart_str_appends(str, " = ");
+		format_default_value(str, default_value);
+	}
+	if (prop->hooks != NULL) {
+		smart_str_appends(str, " {");
+		const zend_function *get_hooked = prop->hooks[ZEND_PROPERTY_HOOK_GET];
+		if (get_hooked != NULL) {
+			if (get_hooked->common.fn_flags & ZEND_ACC_FINAL) {
+				smart_str_appends(str, " final get;");
+			} else {
+				smart_str_appends(str, " get;");
 			}
-			const zend_function *set_hooked = prop->hooks[ZEND_PROPERTY_HOOK_SET];
-			if (set_hooked != NULL) {
-				if (set_hooked->common.fn_flags & ZEND_ACC_FINAL) {
-					smart_str_appends(str, " final set;");
-				} else {
-					smart_str_appends(str, " set;");
-				}
+		}
+		const zend_function *set_hooked = prop->hooks[ZEND_PROPERTY_HOOK_SET];
+		if (set_hooked != NULL) {
+			if (set_hooked->common.fn_flags & ZEND_ACC_FINAL) {
+				smart_str_appends(str, " final set;");
+			} else {
+				smart_str_appends(str, " set;");
 			}
-			smart_str_appends(str, " }");
 		}
+		smart_str_appends(str, " }");
 	}

 	smart_str_appends(str, " ]\n");