skip to Main Content

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


  1. Chosen as BEST ANSWER

    Following a response from the author of phpstan (thanks!) the part I was missing was using the @implements tag.

    /**
     * @implements CastsAttributes<Uuid, UuidInterface>
     */
    class Uuid implements CastsAttributes
    

    This solves the issue up to phpstan max level.


  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search