Skip to content

Conversation

@dereuromark
Copy link
Contributor

Problem

When using phpcbf to fix missing @param annotations in a docblock, the parameters were being inserted in the wrong order.

For example, given this method:

/**
 * @param string $context Context description
 */
private function getProfileConverter(string $profileName, bool $safeMode, string $context = 'article'): DjotConverter

The fix would produce:

/**
 * @param bool $safeMode
 * @param string $profileName
 * @param string $context Context description
 */

Instead of the correct order:

/**
 * @param string $profileName
 * @param bool $safeMode
 * @param string $context Context description
 */

Root Cause

In DocBlockParamSniff::canAddMissingParams(), when multiple parameters need to be inserted before an existing parameter (or at the end of a docblock), they were processed using addContentBefore() in a forward loop. Since addContentBefore() inserts before the same position each time, the result is LIFO (last-in-first-out) order, reversing the parameters.

Solution

Reverse the $pendingInserts array before iterating over it with addContentBefore(). This ensures parameters are inserted in the correct signature order.

Impact

The incorrect parameter order was causing cascading issues with other sniffs:

  • DocBlockParamAllowDefaultValue would detect type mismatches (e.g., bool $safeMode seems to be missing type string)
  • DocBlockParamTypeMismatch would add incorrect union types to "fix" the mismatch
  • This could lead to an infinite loop in phpcbf as sniffs kept trying to fix each other's changes

Testing

The existing test case for middleParamDocumented already covers this scenario and passes with the fix.

When multiple missing parameters need to be inserted before an existing
parameter (or at the end of a docblock), they were being inserted in
reverse order due to how addContentBefore() works - each call inserts
before the same position, resulting in a LIFO order.

The fix reverses the pendingInserts array before iterating, so the
parameters are inserted in the correct signature order.

Example: For a method like:
  function foo(string $a, bool $b, string $c)

With only @param string $c documented, the fix now correctly produces:
  @param string $a
  @param bool $b
  @param string $c

Instead of the previous incorrect output:
  @param bool $b
  @param string $a
  @param string $c

This was causing cascading issues with other sniffs like
DocBlockParamAllowDefaultValue and DocBlockParamTypeMismatch,
which would detect type mismatches due to the wrong parameter order.
@dereuromark dereuromark merged commit a509ed7 into master Dec 3, 2025
4 checks passed
@dereuromark dereuromark deleted the fix/docblock-param-order branch December 3, 2025 15:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants