Background
I am building a class for a laravel system. It is for casting the RamseyUuidUuid
type in laravel models. I also use phpstan
and I seem to be having problems with the generics/templating.
- in the DB, uuid is stored as binary
- when loading or setting,
RamseyUuidUuidInterface
is enforced
The problem
The laravel vendor package has the following interface:
/**
* @template TGet
* @template TSet
*/
interface CastsAttributes
{
/**
* Transform the attribute from the underlying model values.
*
* @param IlluminateDatabaseEloquentModel $model
* @param string $key
* @param mixed $value
* @param array $attributes
* @return TGet|null
*/
public function get($model, string $key, $value, array $attributes);
/**
* Transform the attribute to its underlying model values.
*
* @param IlluminateDatabaseEloquentModel $model
* @param string $key
* @param TSet|null $value
* @param array $attributes
* @return mixed
*/
public function set($model, string $key, $value, array $attributes);
}
My class Uuid
implements this
// ...
use RamseyUuidUuid as RamseyUuid;
use RamseyUuidUuidInterface;
// ...
class Uuid implements CastsAttributes // ...
{
/**
* Cast the given value.
*
* @param Model $model
* @param string $key
* @param string $value
* @param array<mixed> $attributes
* @return UuidInterface
*/
public function get($model, string $key, $value, array $attributes)
{
$uuid = RamseyUuid::fromBytes($value);
return $uuid;
}
/**
* Prepare the given value for storage.
*
* @param Model $model
* @param string $key
* @param UuidInterface $value
* @param array<mixed> $attributes
* @return string
* @throws Exception
*/
public function set($model, string $key, $value, array $attributes)
{
if (!$value instanceof (UuidInterface::class)) {
throw new Exception('The uuid property is not an instance of Ramsey - UuidInterface');
}
return $value->getBytes();
}
When I run phpstan (above level 6), I get the following error:
Class Uuid implements generic interface IlluminateContractsDatabaseEloquentCastsAttributes but does not specify its types: TGet, TSet
I have read the phpstan documentation (generics section, generics by example) several times and I’m simply not sure how it relates to the issue I’m facing. I’ve also used the playground and it also didn’t help me understand the issue.
Question
How do you specify the types of an interface in phpstan
2
Answers
Following a response from the author of phpstan (thanks!) the part I was missing was using the
@implements
tag.This solves the issue up to phpstan max level.
The error has been fixed in this PR. TGet, TSet added in this pull request. I think your error will be fixed in the next release.