Repository navigation
Fix array_map() optimization not resolving the function name of an FCC - #25286
Merged
Merged
Conversation
arnaud-lb
added a commit
that referenced
this pull request
Nov 9, 2026
* PHP-8.6: [ci skip] NEWS Fix array_map() optimization not resolving the function name of an FCC (#25286)
Member
|
Thank you! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 40a8468 (#23254) in 8.6.0RC3. Confirmed by bisect: the parent 31db39c returns the correct value, 40a8468 returns the wrong one. It affects 8.6 (RC3 to RC5) and master, not 8.5 or 8.4.
Verification
\array_map(strtoupper(...), ['a'])withApp\strtoupper\array_map(label(...), [1])withApp\labeluse function Lib\fmt; array_map(fmt(...), [1])\array_map(namespace\label(...), [4]),\label(...), PFApad(?, '!')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.