[php-src] PR #25286: Fix array_map() optimization not resolving the function name of an FCC

From: Date: Sat, 07 Nov 2026 16:23:34 +0000
Subject: [php-src] PR #25286: Fix array_map() optimization not resolving the function name of an FCC
Groups: php.git-pulls 
Request: Send a blank email to git-pulls+get-40397@lists.php.net to get a copy of this message
Pull Request: https://github.com/php/php-src/pull/25286 Author: ChrisAbner In a namespace, or with a use function import, array_map() with a first-class callable called the wrong function. The foreach optimization (added in #20934, extended in #23254) compiles the function name as an expression before the loop. That yields the name as written, with no namespace resolution. The loop then calls it as a global function, ignoring the current namespace, the use function imports and the fallback to the global function. In namespace App with App\strtoupper defined, \array_map(strtoupper(...), ['a']) returned A from the internal function instead of calling App\strtoupper. With use function Lib\fmt, array_map(fmt(...), ...) failed with "undefined function fmt()". For a literal function name in a ZEND_AST_CALL, this keeps the name AST and lets zend_compile_call() resolve it in the loop body, the same way a normal call is resolved, with the namespace fallback. Non-literal names keep the pre-loop evaluation, because they can have side effects and must run once. This mirrors #24244, which did the same for the class name of a static FCC. Resolving the name eagerly with zend_resolve_function_name() was the other option, but it does not express the runtime App\f then \f fallback, so I kept the lazy resolution in the call. Introduced by 40a8468559 (#23254) in 8.6.0RC3. Confirmed by bisect: the parent 31db39c returns the correct value, 40a8468559 returns the wrong one. It affects 8.6 (RC3 to RC5) and master, not 8.5 or 8.4. **Verification** | Case (in namespace App) | Before | After | |---|---|---| | \array_map(strtoupper(...), ['a']) with App\strtoupper | A | APP:a | | \array_map(label(...), [1]) with App\label | global label | App\label | | use function Lib\fmt; array_map(fmt(...), [1]) | undefined function | Lib\fmt | | \array_map(namespace\label(...), [4]), \label(...), PFA pad(?, '!') | already correct | still correct | The new test Zend/tests/array_map_foreach_optimization_function_name.phpt passes, and the 14 existing array_map_foreach_optimization_* tests still pass, without OPcache, with OPcache and with the tracing JIT. On PHP-8.6, Zend/tests, ext/opcache/tests and ext/standard/tests/array run with 0 failures (7360 tests), without OPcache and with it. On master, Zend/tests and ext/opcache/tests run with 0 failures (6572 tests). Not covered: non-literal function names are unchanged. Static method FCCs already resolved correctly (the class name since #24244, the method name is a plain literal). I found this with a deterministic differential testing tool I am developing.

« previous php.git-pulls (#40397) next »