Skip to content

Extend DocBlockTagOrder to class/interface/trait docblocks#59

Merged
dereuromark merged 2 commits into
masterfrom
feature/docblock-tag-order-class-level
May 9, 2026
Merged

Extend DocBlockTagOrder to class/interface/trait docblocks#59
dereuromark merged 2 commits into
masterfrom
feature/docblock-tag-order-class-level

Conversation

@dereuromark
Copy link
Copy Markdown
Contributor

Summary

Currently DocBlockTagOrder only enforces tag ordering on function/method docblocks. Class-level docblocks — typical example, a CakePHP table where association property tags, ORM method tags, behavior mixin tags, and a generic extends tag accumulate over time as IDE-helpers append output — go unsorted.

This PR extends the sniff to also register on T_CLASS, T_INTERFACE, T_TRAIT and adds a separate classOrder property so the class-level order is independent of the function-level one.

Default class order

template, extends, implements, property, property-read, property-write, method, mixin

Reasoning:

  • template / extends / implements first — these declare the class's own type signature (PHPStan/Psalm convention).
  • property next — describes class-level state.
  • method — describes magic / dynamically-generated members.
  • mixin last — additive/late-bound, the class is fully described by the time you read these.

Tags not in the list keep the existing "float to top" behavior.

XML configurability

Both order (function-level, was protected, now public) and classOrder (new) can be overridden:

<rule ref="PhpCollective.Commenting.DocBlockTagOrder">
    <properties>
        <property name="classOrder" type="array" value="extends,property,method,mixin"/>
    </properties>
</rule>

Leading @ on tag names is optional and gets normalized.

Tests

  • DocBlockTagOrderSniffTest is new — there were no existing tests for this sniff. Covers both function-level (regression) and class-level (new) cases plus two configurability variants.
  • All 95 existing sniffer tests still pass; phpstan and phpcs clean.

Adds a configurable `classOrder` property (default: template, extends,
implements, property, property-read, property-write, method, mixin) so
class-level docblocks get the same consistent tag ordering that
function/method docblocks already enforce. Makes the existing `order`
property public so both can be overridden via XML configuration.
dereuromark added a commit to dereuromark/cakephp-ide-helper that referenced this pull request May 9, 2026
Match the class-level tag order proposed in
php-collective/code-sniffer#59:

    template, extends, implements, property, property-read,
    property-write, method, mixin

Previously addBehaviorExtends appended its annotation last, leaving
the extends tag at the bottom of the doc-block. Switch to array_unshift
so a freshly annotated table renders extends first, followed by the
existing property -> method -> mixin sequence (which already matched).

The merge path (appendToExistingDocBlock) still appends new tags after
the last existing tag, so legacy doc-blocks rely on the sniff fixer
for full reordering. Newly generated output is now aligned by
construction.

Test fixtures under tests/test_files/Model/Table updated to reflect
the new order.
When class/interface/trait docblocks have blank " * " separator lines
between tag groups, the reordered output preserved them in now-arbitrary
positions, splitting newly-coherent same-kind tag groups for no reason.

This was caused by getEndIndex() walking back to the previous line
without skipping blank docblock lines, so a tag's content range
extended through any trailing blank line. The rebuilt content then
re-emitted those blanks.

Walk back to the actual content (T_DOC_COMMENT_STRING / TAG) instead.
Multi-line tag content is unaffected.

Adds a fixture that reproduces the case (mirrors a real-world CakePHP
table where IDE-helper output had grown over time with blank-line
separators).
@dereuromark dereuromark merged commit d523fa8 into master May 9, 2026
4 checks passed
@dereuromark dereuromark deleted the feature/docblock-tag-order-class-level branch May 9, 2026 15:09
dereuromark added a commit to dereuromark/cakephp-sandbox that referenced this pull request May 9, 2026
Output of phpcbf using DocBlockTagOrder sniff (extended to class /
interface / trait docblocks via php-collective/code-sniffer#59) — fully
automated, no hand-edits.

For Tables and Entities: groups tags as
extends -> property -> property-read -> method -> mixin (canonical
PHPStan/Psalm class signature first, then state, then magic methods,
then late-bound behaviors).

For controller test classes: floats the not-in-the-list 'uses' tag to
top, leaving 'property' below — matches the sniff's documented
'tags not in the list keep float-to-top behavior'.

Within-method order (canonical CRUD ordering, delete cluster matching
save cluster shape) is intentionally out of scope here — that requires
re-annotating from scratch and is a follow-up.
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.

1 participant