I am trying to figure out how to properly document some code, mostly so that tools like PHPStan and Psalm don’t complain.
Simplified, I have an abstract class that defines methods for setting and getting the state of child classes. The type of that state might be different child class to child class, e.g. a string
in one case, an array
in another, etc..
In reading up on this, I figured the way to accomplish it would be to use @template
on the base class, and more specific param/return types on the children. i.e.:
/**
* The base class, where I use a template and "mixed" param/return types.
*
* @template StateType
*/
abstract class hasState {
/**
* @param StateType $state
*/
public function setState(mixed $value): void;
/**
* @return StateType
*/
public function getState(): mixed;
}
/**
* A child class, where the state is a string.
*/
class stringState implements hasState {
protected string $state = '';
/**
* @param string $value
*/
public function setState(string $value): void
{
$this->state = $value;
}
/**
* @return string
*/
public function getState(): string
{
return $this->state;
}
}
/**
* Another child class, where the state is an array.
*/
class arrayState implements hasState {
protected array $state = [];
/**
* @param array $value
*/
public function setState(array $value): void
{
$this->state = $value;
}
/**
* @return array
*/
public function getState(): array
{
return $this->state;
}
}
In short, this doesn’t work. I get errors like this in Psalm:
Declaration must be compatible with hasState->setState(state: mixed)
psalm: MethodSignatureMismatch: Argument 1 of stringState::setState has wrong type ‘string’, expecting ‘mixed’ as defined by hasState::setState
psalm: MoreSpecificImplementedParamType: Argument 1 of stringStage::setState has the more specific type ‘string’, expecting ‘mixed’ as defined by hasState::setState
Is there no way to accomplish what I’m trying to do: i.e. document and type the params/return values in child classes to use more specific scalar types than the parent?