Commit 87b510be6f2 for php.net

commit 87b510be6f242df7afe1f2d62e0403bb1b157f90
Author: Jorg Adam Sowa <jorg.sowa@gmail.com>
Date:   Mon Aug 3 14:27:32 2026 +0200

    Use zend_hash_find_ptr_lc() for case-insensitive name lookups (batch 2) (#22591)

    Continues #22565 for four sites that were missed: _class_exists_impl(),
    function_exists(), pdo_stmt.c's dbstmt_method_get(), ReflectionClass::
    hasMethod()/getMethod(), and phpdbg's print func/method commands. No
    behavior change.

diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index 87acf073a2d..ed0507e0500 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -1070,7 +1070,6 @@ flf_clean:;

 static zend_always_inline void _class_exists_impl(zval *return_value, zend_string *name, bool autoload, int flags, int skip_flags) /* {{{ */
 {
-	zend_string *lcname;
 	const zend_class_entry *ce;

 	if (ZSTR_HAS_CE_CACHE(name)) {
@@ -1083,14 +1082,10 @@ static zend_always_inline void _class_exists_impl(zval *return_value, zend_strin
 	if (!autoload) {
 		if (ZSTR_VAL(name)[0] == '\\') {
 			/* Ignore leading "\" */
-			lcname = zend_string_alloc(ZSTR_LEN(name) - 1, 0);
-			zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1);
+			ce = zend_hash_str_find_ptr_lc(EG(class_table), ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1);
 		} else {
-			lcname = zend_string_tolower(name);
+			ce = zend_hash_find_ptr_lc(EG(class_table), name);
 		}
-
-		ce = zend_hash_find_ptr(EG(class_table), lcname);
-		zend_string_release_ex(lcname, 0);
 	} else {
 		ce = zend_lookup_class(name);
 	}
@@ -1172,7 +1167,6 @@ ZEND_FUNCTION(function_exists)
 {
 	zend_string *name;
 	bool exists;
-	zend_string *lcname;

 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_STR(name)
@@ -1180,15 +1174,11 @@ ZEND_FUNCTION(function_exists)

 	if (ZSTR_VAL(name)[0] == '\\') {
 		/* Ignore leading "\" */
-		lcname = zend_string_alloc(ZSTR_LEN(name) - 1, 0);
-		zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1);
+		exists = zend_hash_str_find_ptr_lc(EG(function_table), ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1) != NULL;
 	} else {
-		lcname = zend_string_tolower(name);
+		exists = zend_hash_find_ptr_lc(EG(function_table), name) != NULL;
 	}

-	exists = zend_hash_exists(EG(function_table), lcname);
-	zend_string_release_ex(lcname, 0);
-
 	RETURN_BOOL(exists);
 }
 /* }}} */
diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c
index 09b9fd3550e..5731a7e63d3 100644
--- a/ext/pdo/pdo_stmt.c
+++ b/ext/pdo/pdo_stmt.c
@@ -1943,12 +1943,9 @@ static void dbstmt_prop_delete(zend_object *object, zend_string *name, void **ca
 static zend_function *dbstmt_method_get(zend_object **object_pp, zend_string *method_name, const zval *key)
 {
 	zend_function *fbc = NULL;
-	zend_string *lc_method_name;
 	zend_object *object = *object_pp;

-	lc_method_name = zend_string_tolower(method_name);
-
-	if ((fbc = zend_hash_find_ptr(&object->ce->function_table, lc_method_name)) == NULL) {
+	if ((fbc = zend_hash_find_ptr_lc(&object->ce->function_table, method_name)) == NULL) {
 		pdo_stmt_t *stmt = php_pdo_stmt_fetch_object(object);
 		/* instance not created by PDO object */
 		if (!stmt->dbh) {
@@ -1964,14 +1961,13 @@ static zend_function *dbstmt_method_get(zend_object **object_pp, zend_string *me
 			}
 		}

-		if ((fbc = zend_hash_find_ptr(stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT], lc_method_name)) == NULL) {
+		if ((fbc = zend_hash_find_ptr_lc(stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT], method_name)) == NULL) {
 			goto out;
 		}
 		/* got it */
 	}

 out:
-	zend_string_release_ex(lc_method_name, 0);
 	if (!fbc) {
 		fbc = zend_std_get_method(object_pp, method_name, key);
 	}
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c
index 58636c08539..c2dbbb38897 100644
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@ -185,9 +185,9 @@ static zend_always_inline uint32_t prop_get_flags(const property_reference *ref)
 	return ref->prop ? ref->prop->flags : ZEND_ACC_PUBLIC;
 }

-static inline bool is_closure_invoke(const zend_class_entry *ce, const zend_string *lcname) {
+static inline bool is_closure_invoke(const zend_class_entry *ce, const zend_string *name) {
 	return ce == zend_ce_closure
-		&& zend_string_equals(lcname, ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE));
+		&& zend_string_equals_ci(name, ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE));
 }

 static zend_function *_copy_function(zend_function *fptr) /* {{{ */
@@ -4405,9 +4405,8 @@ ZEND_METHOD(ReflectionClass, hasMethod)
 	}

 	GET_REFLECTION_OBJECT_PTR(ce);
-	zend_string *lc_name = zend_string_tolower(name);
-	RETVAL_BOOL(zend_hash_exists(&ce->function_table, lc_name) || is_closure_invoke(ce, lc_name));
-	zend_string_release(lc_name);
+	RETVAL_BOOL(zend_hash_find_ptr_lc(&ce->function_table, name) != NULL
+		|| is_closure_invoke(ce, name));
 }
 /* }}} */

@@ -4423,28 +4422,27 @@ ZEND_METHOD(ReflectionClass, getMethod)
 	}

 	GET_REFLECTION_OBJECT_PTR(ce);
-	zend_string *lc_name = zend_string_tolower(name);
 	zend_function *mptr;
 	zval obj_tmp;
-	if (!Z_ISUNDEF(intern->obj) && is_closure_invoke(ce, lc_name)
+	bool is_invoke = is_closure_invoke(ce, name);
+	if (!Z_ISUNDEF(intern->obj) && is_invoke
 		&& (mptr = zend_get_closure_invoke_method(Z_OBJ(intern->obj))) != NULL)
 	{
 		/* don't assign closure_object since we only reflect the invoke handler
 		   method and not the closure definition itself */
 		reflection_method_factory(ce, mptr, NULL, return_value);
-	} else if (Z_ISUNDEF(intern->obj) && is_closure_invoke(ce, lc_name)
+	} else if (Z_ISUNDEF(intern->obj) && is_invoke
 		&& object_init_ex(&obj_tmp, ce) == SUCCESS && (mptr = zend_get_closure_invoke_method(Z_OBJ(obj_tmp))) != NULL) {
 		/* don't assign closure_object since we only reflect the invoke handler
 		   method and not the closure definition itself */
 		reflection_method_factory(ce, mptr, NULL, return_value);
 		zval_ptr_dtor(&obj_tmp);
-	} else if ((mptr = zend_hash_find_ptr(&ce->function_table, lc_name)) != NULL) {
+	} else if ((mptr = zend_hash_find_ptr_lc(&ce->function_table, name)) != NULL) {
 		reflection_method_factory(ce, mptr, NULL, return_value);
 	} else {
 		zend_throw_exception_ex(reflection_exception_ptr, 0,
 				"Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
 	}
-	zend_string_release(lc_name);
 }
 /* }}} */

diff --git a/sapi/phpdbg/phpdbg_print.c b/sapi/phpdbg/phpdbg_print.c
index 5075ce924d7..0ece32d0b1c 100644
--- a/sapi/phpdbg/phpdbg_print.c
+++ b/sapi/phpdbg/phpdbg_print.c
@@ -153,10 +153,8 @@ PHPDBG_PRINT(method) /* {{{ */

 	if (phpdbg_safe_class_lookup(param->method.class, strlen(param->method.class), &ce) == SUCCESS) {
 		zend_function *fbc;
-		zend_string *lcname = zend_string_alloc(strlen(param->method.name), 0);
-		zend_str_tolower_copy(ZSTR_VAL(lcname), param->method.name, ZSTR_LEN(lcname));

-		if ((fbc = zend_hash_find_ptr(&ce->function_table, lcname))) {
+		if ((fbc = zend_hash_str_find_ptr_lc(&ce->function_table, param->method.name, strlen(param->method.name)))) {
 			phpdbg_notice("%s Method %s (%d ops)",
 				(fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal",
 				ZSTR_VAL(fbc->common.function_name),
@@ -166,8 +164,6 @@ PHPDBG_PRINT(method) /* {{{ */
 		} else {
 			phpdbg_error("The method %s::%s could not be found", param->method.class, param->method.name);
 		}
-
-		zend_string_release(lcname);
 	} else {
 		phpdbg_error("The class %s could not be found", param->method.class);
 	}
@@ -181,7 +177,6 @@ PHPDBG_PRINT(func) /* {{{ */
 	zend_function* fbc;
 	const char *func_name = param->str;
 	size_t func_name_len = param->len;
-	zend_string *lcname;
 	/* search active scope if begins with period */
 	if (func_name[0] == '.') {
 		zend_class_entry *scope = zend_get_executed_scope();
@@ -202,11 +197,8 @@ PHPDBG_PRINT(func) /* {{{ */
 		func_table = EG(function_table);
 	}

-	lcname = zend_string_alloc(func_name_len, 0);
-	zend_str_tolower_copy(ZSTR_VAL(lcname), func_name, ZSTR_LEN(lcname));
-
 	phpdbg_try_access {
-		if ((fbc = zend_hash_find_ptr(func_table, lcname))) {
+		if ((fbc = zend_hash_str_find_ptr_lc(func_table, func_name, func_name_len))) {
 			phpdbg_notice("%s %s %s (%d ops)",
 				(fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal",
 				(fbc->common.scope) ? "Method" : "Function",
@@ -221,8 +213,6 @@ PHPDBG_PRINT(func) /* {{{ */
 		phpdbg_error("Couldn't fetch function %.*s, invalid data source", (int) func_name_len, func_name);
 	} phpdbg_end_try_access();

-	efree(lcname);
-
 	return SUCCESS;
 } /* }}} */