Skip to content

Seal the UnaryOperator/Negative hierarchy (@internal + finalize) - #100

Merged
MidnightDesign merged 1 commit into
masterfrom
95-seal-the-unaryoperatornegative-hierarchy-internal-+-finalize-replaces-dangling-83
Jul 23, 2026
Merged

Seal the UnaryOperator/Negative hierarchy (@internal + finalize)#100
MidnightDesign merged 1 commit into
masterfrom
95-seal-the-unaryoperatornegative-hierarchy-internal-+-finalize-replaces-dangling-83

Conversation

@MidnightDesign

Copy link
Copy Markdown
Contributor

Closes #95.

Scoped for the 0.3.0 breaking release.

What changed

src/UnaryOperator.php

  • Added @internal + @psalm-internal Eventjet\Ausdruck, taking the base off the promised surface.
  • Finalized __toString() and equals() to match the already-sealed BinaryOperator.
  • Rewrote the docblock: dropped the section explaining why the class couldn't be internal (the $expression-name-is-fixed and methods-can't-be-final constraints) and the dangling #83 / "next major" deferral. Kept the still-true token()-is-protected rationale.

src/Negative.php

  • Added @internal + @psalm-internal Eventjet\Ausdruck.

Not was already born @internal, so the hierarchy is now sealed consistently with BinaryOperator.

Why now, not "next major"

The old docblock deferred sealing to a literal 1.0 and pointed at a dangling eventjet/ausdruck#83 (no such issue/PR exists). Per docs/BACKWARD-COMPATIBILITY.md, on the 0.x line the minor is the compatibility boundary — 0.3.0 is the breaking window, so this belongs here rather than waiting years for 1.0.

BC impact

Structural break: removes Negative/UnaryOperator and their inherited members from the public API and finalizes previously-published methods. This is the "finalizing a published method breaks BC even on a final class" case and can only land in a breaking minor. Roave's BC checker will (correctly) flag it.

Verification

  • cs-check, psalm, phpstan, phpunit (1131 tests) — all green.
  • infection-diff — 0 mutations on the changed lines (docblock + final keywords carry no mutable logic), passes with --ignore-msi-with-no-mutations.

🤖 Generated with Claude Code

https://claude.ai/code/session_013Aqoim7pUMKSoPCe4i9h9F

Mark UnaryOperator and Negative @internal + @psalm-internal, and
finalize UnaryOperator::__toString() and equals() to match the
already-sealed BinaryOperator. This removes Negative/UnaryOperator and
their inherited members from the public API.

The old docblock documented this as the intended end state but deferred
it to "the next major", pointing at a dangling eventjet/ausdruck#83.
Per docs/BACKWARD-COMPATIBILITY.md the minor is the 0.x compatibility
boundary, so 0.3.0 is the breaking window this belongs in. Rewrote the
docblock accordingly, dropping the now-obsolete not-yet-internal
rationale and keeping the still-true token()-is-protected note.

Not was already born @internal, so the hierarchy is now sealed
consistently with BinaryOperator.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013Aqoim7pUMKSoPCe4i9h9F
@MidnightDesign
MidnightDesign merged commit 48b1847 into master Jul 23, 2026
25 checks passed
@MidnightDesign
MidnightDesign deleted the 95-seal-the-unaryoperatornegative-hierarchy-internal-+-finalize-replaces-dangling-83 branch July 23, 2026 14:40
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.

Seal the UnaryOperator/Negative hierarchy (@internal + finalize) — replaces dangling #83

1 participant