From a65d5dc5916f5e78f02685bcacc4add90646e296 Mon Sep 17 00:00:00 2001 From: Claudio Dekker <1752195+claudiodekker@users.noreply.github.com> Date: Sat, 10 Oct 2026 18:54:00 +0200 Subject: [PATCH] Fix array_map() optimization not resolving the class name of a static FCC --- NEWS | 2 + ...y_map_foreach_optimization_class_name.phpt | 74 +++++++++++++++++++ Zend/zend_compile.c | 10 ++- 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/array_map_foreach_optimization_class_name.phpt diff --git a/NEWS b/NEWS index a4b3d143c37c..dd6f746d3928 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,8 @@ PHP NEWS the next smaller bin in its larger bin, which efree_size() then freed into the wrong one. (Marc Bennewitz) . Fix throwing behaviour with recursive arrays in VM. (ndossche) + . Fixed array_map() optimization not resolving the class name of a static + first-class callable. (claudiodekker) - FPM: . Fixed bug GH-24229 (fcgi_close() passes shutdown() a literal 1, which is diff --git a/Zend/tests/array_map_foreach_optimization_class_name.phpt b/Zend/tests/array_map_foreach_optimization_class_name.phpt new file mode 100644 index 000000000000..fab9c51ee552 --- /dev/null +++ b/Zend/tests/array_map_foreach_optimization_class_name.phpt @@ -0,0 +1,74 @@ +--TEST-- +array_map(): foreach optimization resolves the class name of a static FCC +--FILE-- + +--EXPECT-- +array(1) { + [0]=> + int(2) +} +array(1) { + [0]=> + int(3) +} +array(1) { + [0]=> + int(3) +} +array(1) { + [0]=> + int(3) +} +array(1) { + [0]=> + int(2) +} +array(1) { + [0]=> + int(2) +} +array(1) { + [0]=> + int(2) +} +array(1) { + [0]=> + int(2) +} diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index fe8f978ff59c..40f90e384754 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -5375,7 +5375,15 @@ static zend_result zend_compile_func_array_map(znode *result, zend_ast_list *arg /* Evaluate class name */ znode class_node; - if (callback->kind == ZEND_AST_STATIC_CALL) { + if (callback->kind == ZEND_AST_STATIC_CALL + && callback->child[0]->kind == ZEND_AST_ZVAL + && Z_TYPE_P(zend_ast_get_zval(callback->child[0])) == IS_STRING + && zend_get_class_fetch_type(zend_ast_get_str(callback->child[0])) == ZEND_FETCH_CLASS_DEFAULT) { + /* Resolve the name against the namespace and imports, as compiling it + * as an expression would yield the unresolved string. */ + class_node.op_type = IS_CONST; + ZVAL_STR(&class_node.u.constant, zend_resolve_class_name_ast(callback->child[0])); + } else if (callback->kind == ZEND_AST_STATIC_CALL) { znode result; zend_compile_expr(&result, callback->child[0]); if (result.op_type == IS_CONST || result.op_type == IS_TMP_VAR) {