Skip to content

Expand Output Interface/Methods#124

Merged
zanbaldwin merged 2 commits into
6.xfrom
z/octets
Jun 17, 2026
Merged

Expand Output Interface/Methods#124
zanbaldwin merged 2 commits into
6.xfrom
z/octets

Conversation

@zanbaldwin

Copy link
Copy Markdown
Member

No description provided.

@zanbaldwin zanbaldwin self-assigned this Jun 17, 2026
@greptile-apps

greptile-apps Bot commented Jun 17, 2026

Copy link
Copy Markdown

Greptile Summary

This PR expands the OutputInterface and Output6Interface contracts with three new methods — getOctets(), getSegments(), and toString() — and refactors __toString() across all three version classes to delegate to the new toString(). It also centralises the mb_str_split/str_split fallback pattern into MbString::split(), replacing ad-hoc ternaries in Binary and ConsistentFormatter.

  • getOctets() is provided in AbstractIP and overridden in Multi to return the four IPv4 octets for embedded addresses (delegating to a temporary IPv4 object) or sixteen IPv6 octets otherwise.
  • getSegments() is added to IPv6, splitting the 16-byte binary into eight 2-byte words with bit-shifting; Multi overrides it to throw WrongVersionException(6, 4, …) for embedded IPv4 addresses, consistent with the existing pattern in isUniqueLocal() and similar methods.
  • The ip-doctrine companion package is unaffected: it only calls getBinary(), getVersion(), and string casting — none of which changed in observable behaviour.

Confidence Score: 5/5

Safe to merge — all new methods are additive, follow established patterns, and are covered by tests including edge cases and round-trip assertions.

The new methods are purely additive on the @experimental contracts, the Multi overrides mirror the existing delegation pattern used by a dozen other methods in the same class, the centralisation of MbString::split() is a straight refactor of code that was already in the codebase, and the tests cover both the happy path and the exception-throwing branches for embedded IPv4 addresses.

No files require special attention.

Important Files Changed

Filename Overview
src/Util/MbString.php Adds MbString::split() centralising the mb_str_split/str_split fallback pattern; the function_exists with leading backslash is consistent with getLength()/subString() in the same class.
src/AbstractIP.php Adds getOctets() using the new MbString::split() helper; straightforward conversion of each binary byte to an integer via ord().
src/Contracts/OutputInterface.php Adds getOctets() and toString() to the @experimental interface; toString() is documented as the canonical string form re-parseable via fromProtocol().
src/Contracts/Output6Interface.php Adds getSegments() with @throws WrongVersionException for multi-embedded IPv4 addresses; return type documented as list<int<0, 65535>>.
src/Version/IPv6.php Adds getSegments() splitting the 16-byte binary into 2-byte words and bit-shifting; refactors __toString() to delegate to new toString().
src/Version/Multi.php Overrides getOctets() to return 4 octets for embedded IPv4 and 16 for pure IPv6; overrides getSegments() to throw WrongVersionException(6, 4, …) consistent with isUniqueLocal() and similar methods.
src/Version/IPv4.php Refactors __toString() to delegate to new toString() which returns the dot-notation address.
src/Formatter/ConsistentFormatter.php Replaces str_split($hex, 4) with MbString::split($hex, 4) to guard against mbstring function overloading; behaviour is identical for ASCII hex strings.
src/Util/Binary.php Replaces two inline mb_str_split/str_split ternaries with MbString::split() calls; early-return guard ensures split is never called on an empty string.
tests/Version/MultiTest.php Adds tests for toString(), getOctets(), and getSegments() including non-default strategy, exception cases, and round-trip re-parsing; dual annotation follows project convention.
tests/Version/IPv4Test.php Adds testToStringReturnsCanonicalNotation and testGetOctets with data-provider coverage; round-trip assertion confirms re-parseability via fromProtocol().
tests/Version/IPv6Test.php Adds testToStringReturnsCanonicalNotation, testGetOctets, and testGetSegments with data-provider coverage; all segment values independently verified.

Class Diagram

%%{init: {'theme': 'neutral'}}%%
classDiagram
    class OutputInterface {
        <<interface>>
        +getBinary() string
        +getOctets() list~int~
        +toString() string
        +__toString() string
    }
    class Output6Interface {
        <<interface>>
        +getCompactedAddress() string
        +getExpandedAddress() string
        +getSegments() list~int~
    }
    class AbstractIP {
        +getBinary() string
        +getOctets() list~int~
    }
    class IPv4 {
        +toString() string
        +__toString() string
    }
    class IPv6 {
        +getSegments() list~int~
        +toString() string
        +__toString() string
    }
    class Multi {
        +getOctets() list~int~
        +getSegments() list~int~
        +toString() string
        +__toString() string
    }

    Output6Interface --|> OutputInterface
    AbstractIP ..|> OutputInterface
    IPv4 --|> AbstractIP
    IPv6 --|> AbstractIP
    IPv6 ..|> Output6Interface
    Multi --|> IPv6
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
classDiagram
    class OutputInterface {
        <<interface>>
        +getBinary() string
        +getOctets() list~int~
        +toString() string
        +__toString() string
    }
    class Output6Interface {
        <<interface>>
        +getCompactedAddress() string
        +getExpandedAddress() string
        +getSegments() list~int~
    }
    class AbstractIP {
        +getBinary() string
        +getOctets() list~int~
    }
    class IPv4 {
        +toString() string
        +__toString() string
    }
    class IPv6 {
        +getSegments() list~int~
        +toString() string
        +__toString() string
    }
    class Multi {
        +getOctets() list~int~
        +getSegments() list~int~
        +toString() string
        +__toString() string
    }

    Output6Interface --|> OutputInterface
    AbstractIP ..|> OutputInterface
    IPv4 --|> AbstractIP
    IPv6 --|> AbstractIP
    IPv6 ..|> Output6Interface
    Multi --|> IPv6
Loading

Reviews (2): Last reviewed commit: "refactor(util): ♻️ centralise byte-strin..." | Re-trigger Greptile

Comment thread src/Util/MbString.php
Comment thread src/Version/IPv6.php
@zanbaldwin zanbaldwin merged commit c64438e into 6.x Jun 17, 2026
24 checks passed
@zanbaldwin zanbaldwin deleted the z/octets branch June 17, 2026 11:06
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