Repository navigation
Description
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, however, do not necessarily support all these input representations.
For example, a text-based strategy may only accept strings, while another strategy may operate on structured arrays or objects.
Requiring every strategy to expose the complete string|array|object union weakens the strategy contract and forces individual implementations to handle input types they do not actually support.
PHP parameter variance does not allow an implementation to narrow such a parameter type. A strategy implementing a generic contract accepting string|array|object therefore cannot redefine its method to accept only string.
Objective
Introduce explicit input contracts for decoder strategies while preserving a unified public Decoder API.
Each strategy must explicitly declare the input representation or representations it supports.
The Decoder remains responsible for accepting the public set of supported input types and delegating the input only to a compatible strategy.
Target architecture
DecoderStrategyInterface becomes the common marker interface for all decoder strategies.
Specialized interfaces define the actual decoding contracts:
interface DecoderStrategyInterface
{
}
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 input contracts.
For example, a strategy supporting both textual and structured representations may implement:
final class ExampleStrategy implements
StringDecoderStrategyInterface,
ArrayDecoderStrategyInterface
{
public function decode(string|array $data): SpatialInterface
{
// ...
}
}Decoder contract
The main decoder keeps the unified public API:
public function decode(string|array|object $data): SpatialInterface;Before delegating the decoding operation, the Decoder must verify that the configured strategy implements the interface corresponding to the provided input type.
The compatibility mapping is:
| Input | Required strategy contract |
|---|---|
string |
StringDecoderStrategyInterface |
array |
ArrayDecoderStrategyInterface |
object |
ObjectDecoderStrategyInterface |
When the configured strategy does not support the provided input representation, the decoder must reject the call before invoking the strategy.
Exception contract
Introduce:
final class InvalidArgumentException extends \InvalidArgumentException implements DecoderExceptionInterface
{
}This exception is raised when the supplied input type is incompatible with the currently configured decoder strategy.
This allows consumers to handle the exception either through the standard SPL hierarchy:
catch (\InvalidArgumentException $exception)or through the Spatial Decoder exception contract:
catch (DecoderExceptionInterface $exception)Acceptance criteria
DecoderStrategyInterfaceis the common parent contract for every decoder strategy.- Dedicated strategy interfaces exist for
string,array, andobjectinputs. - Each strategy explicitly implements every input contract it supports.
- A strategy may implement multiple input contracts.
- Strategy
decode()signatures use the narrowest native PHP type compatible with their declared contracts. DecoderInterface::decode()continues to acceptstring|array|object.Decoderdelegates only when the configured strategy supports the supplied input representation.- An incompatible input/strategy combination throws the library
InvalidArgumentException. InvalidArgumentExceptionextends\InvalidArgumentExceptionand implementsDecoderExceptionInterface.- Existing decoder strategies are migrated to the appropriate specialized contracts.
- Tests cover every supported input/strategy combination.
- Tests cover rejection of incompatible input/strategy combinations.
- Tests cover strategies implementing more than one input contract.
- Public documentation explains the distinction between the generic
Decodercontract and the specialized strategy contracts. - Strategy implementation documentation explains how third-party strategies declare their supported input representations.
- All existing quality and CI gates remain green.
Compatibility considerations
This Epic changes the public strategy API and must therefore be treated as a backward compatibility break if DecoderStrategyInterface is already part of the stable public API.
The unified DecoderInterface::decode() signature remains unchanged.
The migration impact is primarily limited to implementations of DecoderStrategyInterface, which must explicitly select one or more specialized input contracts.
Out of scope
This Epic does not introduce new input representations.
It does not change the spatial objects returned by decoding strategies.
It does not define format-specific validation rules. Validation of the content itself remains the responsibility of each strategy.
It does not introduce automatic conversion between input representations. The Decoder only verifies compatibility and delegates decoding.
Activity