Skip to content

Story: Introduce typed strategy contracts and decoder dispatch #17

Closed

Description

@Alexandre-T

Context

The decoder currently exposes a generic input contract allowing data to be provided as a string, an array, or an object.

public function decode(string|array|object $data): SpatialInterface;

Decoder strategies do not necessarily support all these input representations.

PHP parameter variance prevents a strategy implementing this generic contract from narrowing its decode() parameter to the input type it actually supports.

The strategy contracts must therefore explicitly describe their supported input representation while the main Decoder keeps its unified public API.

Objective

Introduce specialized decoder strategy interfaces for string, array, and object inputs and make the central Decoder responsible for validating compatibility and dispatching the decoding operation.

Implementation

Make DecoderStrategyInterface the common marker interface for all decoder strategies.

Introduce the following specialized contracts:

interface StringDecoderStrategyInterface extends DecoderStrategyInterface
{
    public function decode(string $data): SpatialInterface;
}

interface ArrayDecoderStrategyInterface extends DecoderStrategyInterface
{
    /**
     * @param array<string, mixed> $data
     */
    public function decode(array $data): SpatialInterface;
}

interface ObjectDecoderStrategyInterface extends DecoderStrategyInterface
{
    public function decode(object $data): SpatialInterface;
}

A strategy may implement one or several specialized contracts.

Keep the public decoder contract unchanged:

public function decode(string|array|object $data): SpatialInterface;

Decoder::decode() must verify that the configured strategy implements the contract corresponding to the supplied input:

Input Required strategy contract
string StringDecoderStrategyInterface
array ArrayDecoderStrategyInterface
object ObjectDecoderStrategyInterface

When compatible, the decoder delegates the input to the strategy.

When incompatible, the strategy must not be invoked.

Exception

Introduce:

final class InvalidArgumentException extends \InvalidArgumentException implements DecoderExceptionInterface
{
}

The exception must be thrown when the PHP type supplied to Decoder::decode() is part of its public contract but is not supported by the currently configured strategy.

Acceptance criteria

  • DecoderStrategyInterface is the common marker interface for decoder strategies.
  • StringDecoderStrategyInterface accepts string.
  • ArrayDecoderStrategyInterface accepts array.
  • ObjectDecoderStrategyInterface accepts object.
  • All specialized interfaces extend DecoderStrategyInterface.
  • A strategy may implement multiple specialized interfaces.
  • DecoderInterface::decode() continues to accept string|array|object.
  • Decoder::decode() checks compatibility between the supplied input and the configured strategy.
  • Compatible inputs are delegated to the strategy.
  • Incompatible inputs are rejected before the strategy is invoked.
  • An incompatible input throws the library InvalidArgumentException.
  • InvalidArgumentException extends \InvalidArgumentException.
  • InvalidArgumentException implements DecoderExceptionInterface.
  • Tests cover each specialized input contract.
  • Tests cover incompatible input/strategy combinations.
  • Tests cover a strategy implementing multiple input contracts.
  • All existing quality and CI gates remain green.

Out of scope

  • Migration of existing concrete decoder strategies to the new contracts.
  • Public API documentation.
  • New input representations.
  • Automatic conversion between input representations.
  • Changes to format-specific decoding or validation rules.

Activity

  1. self-assigned this
    on Sep 26, 2026
  2. changed the title [-]Introduce typed strategy contracts and decoder dispatch[/-] [+]Story: Introduce typed strategy contracts and decoder dispatch[/+] on Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

impact:apiAffects the public API

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions