Fix ConsistentIndent mis-indenting PHP 8.4 property hooks - #76
Merged
Conversation
The sniff derived its expected indent from the size of a token's conditions map. PHP_CodeSniffer does not model property hooks as scopes: their braces carry bracket opener and closer metadata but contribute nothing to conditions, so every token inside a hook block reported the same depth as the property itself. Only the second hook actually tripped it. Lines preceded by an opening brace are let through as continuations, and the hook bodies and closing braces are skipped, which leaves just the line after the first hook's closing brace. That was enough for phpcbf to dedent set to the property's own level while get, the bodies and every brace stayed put, producing exactly the inconsistent indentation this sniff exists to prevent. Expected indent now also counts enclosing curly brace pairs that phpcs paired but did not map to a scope. That repairs the depth model rather than special casing one syntax. The ranges are collected in a single pass and cached per file alongside the token count, matching how arrow function scopes are already handled, so nothing walks the file per line. The fixtures gain a correctly indented hook pair, which must stay untouched, and a misindented one, which proves the sniff still sees inside hook bodies rather than going blind there.
There was a problem hiding this comment.
Pull request overview
This PR fixes ConsistentIndent mis-indenting PHP 8.4 property hooks by repairing the sniff’s indentation depth model when PHPCS pairs curly braces (bracket_opener/bracket_closer) but does not model them as scopes (so they don’t appear in conditions).
Changes:
- Extend expected-indent calculation to include enclosing “unscoped” curly-brace pairs (cached per file, self-invalidating on token-count change).
- Add fixtures covering correctly-indented and misindented property-hook blocks, and update the expected error count accordingly.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| PhpCollective/Sniffs/WhiteSpace/ConsistentIndentSniff.php | Adjusts expected-indent calculation by adding a cached count of enclosing unscoped curly-brace ranges. |
| tests/_data/ConsistentIndent/before.php | Adds PHP 8.4 property hook examples (one correct, one intentionally misindented) to exercise the sniff and fixer. |
| tests/_data/ConsistentIndent/after.php | Expected fixed output for the misindented hook-body line; keeps the correctly-indented hook block unchanged. |
| tests/PhpCollective/Sniffs/WhiteSpace/ConsistentIndentSniffTest.php | Updates expected error count to account for the newly-added misindent fixture case. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
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.
ConsistentIndentdedents the second hook of a PHP 8.4 property hook block, and phpcbf applies it.Input:
Reported, and auto-fixed:
Output -
setmoved to 4 whileget, both bodies and every closing brace stayed at 8:get { return $this->label; } set { $this->label = $value; }Cause
getExpectedIndent()returnedcount($token['conditions']). PHP_CodeSniffer 4.x does not model property hooks as scopes - the hook braces get noscope_opener/scope_closerand add no entry toconditions. Dumping the parsed tokens shows every token inside both hooks carryingconditions=[T_CLASS], so the whole block reads as one level deep.Only the
setline surfaced it. Lines whose previous content token is an opening brace pass the continuation check, and lines starting with}return early, which leaves exactly the line following the first hook's closing brace. A property with three hooks reports it twice.Fix
The braces are paired even though they are not scopes - they carry
bracket_openerandbracket_closer. Expected indent now adds the number of enclosing curly-brace pairs that phpcs paired but did not map to a scope, so the depth model is repaired rather than special-cased for one syntax.The ranges are collected in one pass and cached per file with the token count alongside, so the cache self-invalidates when phpcbf re-tokenizes mid fix-loop. That is the same approach already used for arrow function scopes, and it keeps the per-line cost off the file size.
Coverage
The existing fixtures gain a correctly indented hook pair, which must come through byte-identical, and a deliberately misindented one, which proves the sniff still reports inside hook bodies instead of going blind there. Every pre-existing case in those fixtures is untouched - that is the regression guard on the depth-model change.