Skip to content

Cover the reference operator in ImplicitCastSpacing - #82

Merged
dereuromark merged 1 commit into
masterfrom
unary-reference-operator
Aug 6, 2026
Merged

Cover the reference operator in ImplicitCastSpacing#82
dereuromark merged 1 commit into
masterfrom
unary-reference-operator

Conversation

@dereuromark

Copy link
Copy Markdown
Contributor

- $a, ! $b and @ f() are already handled by PhpCollective.WhiteSpace.ImplicitCastSpacing. The reference marker is the same shape, so it joins that sniff rather than arriving as a new one.

This closes the last gap against psr2r-sniffer's UnaryOperatorSpacing, which can now be deleted there - & was the only construct it still covered that this standard did not:

Construct PSR2R's sniff this sniff, before this sniff, after
- $a yes yes yes
! $b no yes yes
@ f() yes yes yes
& $list yes no yes

Reference or bitwise and

The preceding token is not enough on its own. In function f(array & $items) the marker follows a type hint, and a type hint looks exactly like the left operand of a bitwise and.

So a reference is a & that stands in front of a variable - or the ellipsis of a by-reference variadic - and either follows something that cannot end a value, or sits inside a parameter list. Requiring the variable on the right is what keeps a default value out of it:

$bad = & $list;                                   // reported
foreach ($items as & $item) {}                    // reported
foreach ($items as $k => & $v) {}                 // reported
function f(array & $items) {}                     // reported
function g(& ...$args) {}                         // reported

$ok = &$list;                                     // untouched
$okBitwise = $a & $b;                             // untouched
$okBoolean = $a && $b;                            // untouched
function h(int $x = self::A & self::B) {}         // untouched

Every one of those is in the fixture.

The sniff already owned this shape for `!`, `@` and unary minus, so the
reference marker joins it rather than arriving as a separate sniff. That also
lets psr2r-sniffer, which enables this rule already, drop its own
UnaryOperatorSpacing: the reference marker was the only thing it still covered
that nothing here did.

Telling a reference from a bitwise and needs more than the preceding token. A
type hint precedes the marker in `function f(array & $items)`, and a type hint
reads exactly like the left operand of a bitwise and. So a reference is one
that stands in front of a variable, or the ellipsis of a by-reference variadic,
and either follows something that cannot end a value or sits in a parameter
list. Requiring the variable on the right keeps a default such as
`function f(int $x = self::A & self::B)` out of it.

Covered by fixtures: plain `$a = & $list`, by-reference foreach in both forms,
a typed parameter, a variadic, and the bitwise and boolean operators that must
stay untouched.
Copilot AI lite review requested due to automatic review settings August 6, 2026 13:59
@dereuromark
dereuromark merged commit a6244e4 into master Aug 6, 2026
6 checks passed
@dereuromark
dereuromark deleted the unary-reference-operator branch August 6, 2026 14:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Extends PhpCollective.WhiteSpace.ImplicitCastSpacing to also enforce no whitespace after the reference marker (&) when it is used as a by-reference operator, while leaving bitwise & spacing untouched.

Changes:

  • Registers T_BITWISE_AND and adds logic to treat & as an implicit-cast-style operator only when it’s a reference marker.
  • Introduces isReferenceOperator() to distinguish reference & from bitwise & (including parameter-list handling).
  • Expands the fixture and updates expected fixable error counts accordingly.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
PhpCollective/Sniffs/WhiteSpace/ImplicitCastSpacingSniff.php Adds & handling with reference-vs-bitwise disambiguation.
tests/PhpCollective/Sniffs/WhiteSpace/ImplicitCastSpacingSniffTest.php Updates expected error/fix counts to match new fixture cases.
tests/_data/ImplicitCastSpacing/before.php Adds reference-operator spacing violations to be detected/fixed.
tests/_data/ImplicitCastSpacing/after.php Adds the expected fixed output for the new reference-operator cases.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +26 to +33
$reference = & $items;
$validReference = &$items;
$validBitwiseAnd = $count & $mask;

foreach ($items as & $item) {
$item = (int)$item;
}
unset($item);
dereuromark added a commit that referenced this pull request Aug 6, 2026
The reference marker added in #82 only matched in front of a variable or a
variadic ellipsis, so `function & name()` slipped through - the name is not a
variable. That form is checked first now, keyed on the preceding function,
closure or arrow-function keyword.

Found while retiring psr2r-sniffer's UnaryOperatorSpacing against this rule:
return by reference was the one construct it still reported that this sniff
did not.
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