Report only accumulating array_merge in loops, cover while and do-while - #503
Open
lbajsarowicz wants to merge 1 commit into
Open
Report only accumulating array_merge in loops, cover while and do-while#503lbajsarowicz wants to merge 1 commit into
lbajsarowicz wants to merge 1 commit into
Conversation
ForeachArrayMergeSniff warned about every array_merge token inside a for or foreach body. Only the accumulating shape - the result merged back into one of the call's own arguments - grows the array on every iteration, so calls like `$row = array_merge($defaults, $data);` were reported without anything to fix, and calls that reset the target earlier in the same iteration were too. At the same time while and do-while bodies were never looked at. The sniff now reports a call when: - the assignment target is one of the arguments of the same call, or the result is passed to a setter fed by a getter on the same object, and - the target is not unconditionally overwritten earlier in the iteration, and is not the value or key variable of the enclosing foreach. Loop tokens registered are now T_FOREACH, T_FOR, T_WHILE and T_DO, and each call is reported by the innermost loop that contains it.
This was referenced Aug 5, 2026
Author
|
Three examples of the shape this PR is meant to keep catching, each with before/after numbers, opened against
All three carried |
1 task
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.
Description
Magento2.Performance.ForeachArrayMergewarns on everyarray_mergetoken that appearsinside a
fororforeachbody. Two consequences:It over-reports. Only the accumulating shape — the result merged back into one of the
call's own arguments — makes the loop quadratic. A call like
is flagged today with nothing to fix, and so is a call whose target is rebuilt from scratch
earlier in the same iteration:
magento/magento22.4-develop currently carries 77// phpcs:ignore Magento2.Performance.ForeachArrayMergeannotations. Suppressing a warning line by line is the only available answer when the sniff
cannot tell the two shapes apart, and every suppression also hides the real finding if the
code later changes.
It under-reports.
register()only returnsT_FOREACHandT_FOR, sowhileanddo/whilebodies are never inspected.Magento\Framework\View\Design\Fallback\Rule\Theme::getPatternDirs()accumulates into
$resultinside awhileloop and has never been reported.What changed
A call is reported when it accumulates:
$var,$this->property,self::$propertyand array offsets such as$data['rows']; or(
$builder->setColumns(array_merge($builder->getColumns(), $columns)), the case alreadycovered by the fixture from Better solution for fixing array_merge in loop #195);
and it is not obviously reset per iteration:
nesting level — a preceding
$target = array_merge($target, ...)still counts asaccumulation, so consecutive merges into one accumulator are both reported;
foreach.register()now returnsT_FOREACH,T_FOR,T_WHILEandT_DO, and every call isreported by the innermost loop that contains it. The
whileof ado/whilehas no scopeof its own, so the
T_DObody is what gets inspected — no double reporting. Inline(brace-less) loop bodies keep being skipped, as before. A method or function named
array_mergeis no longer mistaken for the global function.The warning code and message are unchanged, so existing suppressions and baselines keep
working.
Effect on magento/magento2 2.4-develop
Measured with this branch against
magento/magento2@b977e369455(
app/code/Magento,lib/internal/Magento,setup/src):--ignore-annotations53 of the 126 raw detections were calls that cannot grow anything; one new finding appears
(
Framework/View/Design/Fallback/Rule/Theme.php:78, thewhileaccumulator above). Noaccumulating call that the sniff reported before is missed.
Manual testing scenarios
vendor/bin/phpunit --filter ForeachArrayMerge— the fixture grew from 3 to 11 expectedwarnings and now also pins the shapes that must stay silent (constant-work merge, target
reset per iteration,
foreachvalue/key variable, setter fed by a different object,method named
array_merge).vendor/bin/phpcs --standard=Magento2 --sniffs=Magento2.Performance.ForeachArrayMerge <path to magento2>before and after, to reproduce the table above.
vendor/bin/phpcs --standard=Magento2 Magento2/Sniffsand--standard=Magento2Framework Magento2/Sniffs— clean.Full
vendor/bin/phpunitalso fails 9Magento2\Tests\Eslint\*tests locally withoutnpm install; those fail identically ondevelopand are unrelated to this change.Contribution checklist