I'm getting used to use psalm, but I'm facing an issue. I already have this structure in C# and it worked out for me. I didn't really get how I could solve this using psalm.
I have a ContextInterface
and another implementing it.
interface ContextInterface { public function getProductId(): int; }
interface SingleContextInterface extends ContextInterface { public function getWidth(): int; }
Additionally I have strategy interfaces for them.
/**
* @template-covariant T as ContextInterface
* @psalm-immutable
*/
interface CalculatorInterface
{
/**
* @psalm-param T $context
*/
public function getPrice(ContextInterface $context): int;
}
/**
* @template T as SingleContextInterface
* @template-extends CalculatorInterface<T>
* @psalm-immutable
*/
interface SingleDimensionalPriceCalculator extends CalculatorInterface { }
And one class implementing the interface:
/**
* @template T as SingleContextInterface
* @template-implements SingleDimensionalPriceCalculator<T>
* @psalm-immutable
*/
class SingleDimensionCalculator implements SingleDimensionalPriceCalculator
{
/**
* @psalm-param SingleContextInterface $context
*/
public function getPrice(ContextInterface $context): int
{
$context->getWidth();
return 1;
}
}
For the getWidth()
method call I receive the following error:
ERROR: ImpureMethodCall - 37:19 - Cannot call an possibly-mutating method SingleContextInterface::getWidth from a mutation-free context
The example on psalm.dev
Of course the real case is more complicated and contains more interfaces.
I figured, the problem was that I marked the template on CalculatorInterface
as covariant. I can just extend it without, it being covariant.
Example on psalm.dev