-
Notifications
You must be signed in to change notification settings - Fork 665
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Templates on static methods yet again #7975
Comments
I found these snippets: https://psalm.dev/r/4cf10dedf9<?php
/**
* @template T
*/
interface PersistableEntityInterface
{
/**
* Returns a DTO containing state of the entity so that it can be saved to a persistent storage.
* @return T
*/
public function saveState(): mixed;
/**
* Constructs entity restoring the state from DTO taken from a storage.
* @param T $state
*/
public static function restoreState(mixed $state): static;
}
/** @template-implements PersistableEntityInterface<UserState> */
final class User implements PersistableEntityInterface
{
public function __construct(
private readonly string $id,
private readonly string $name,
) {}
public function name(): string
{
return strtoupper($this->name);
}
public function saveState(): UserState
{
return new UserState($this->id, $this->name);
}
public static function restoreState(mixed $state): self
{
return new self($state->id, $state->name);
}
}
class UserState
{
public function __construct(
public readonly string $id,
public readonly string $name,
) {}
}
class UserRepository
{
/** @var array<string, UserState> */
private array $users = [];
public function getById(string $id): User
{
return User::restoreState($this->users[$id] ?? throw new \RuntimeException);
}
public function save(User $user): void
{
$userState = $user->saveState();
$this->users[$userState->id] = $userState;
}
}
|
I was trying to setup Psalm on a codebase that's already using PHPStan (I figured it would be good to check things with both tools), and this is one of the main things blocking me from doing so. I have several abstract classes that define template types used in the params of their static methods. For (an abridged) example: /**
* @template T of Table
* @template R of array<non-empty-string, mixed>
*/
abstract class Model {
/**
* @phpstan-param R $row
*
* @phpstan-return self<T, R>
*/
abstract public static function fromRow(array $row): self;
} The param type of the |
I confirm the issue and join the request of how to do templating for static properties. |
I found these snippets: https://psalm.dev/r/9a4c417e38<?php
/**
* @template T
*/
class Foo {
/**
* @var array<class-string<T>, mixed>
*/
private static array $classMap = [];
}
|
@orklah Do you think introducing something like |
Possibly. Frankly, this is kinda over my head. It's a design choice that was made before I started actively contributing and I would have no idea how to change that meaningfully |
This also affects static properties as seen in https://psalm.dev/r/047cddc9ac. Having a static template annotation won't help when we have mixed usage I suppose (storing values from static context but using them in instanced context). |
I found these snippets: https://psalm.dev/r/047cddc9ac<?php
declare(strict_types=1);
/** @template T */
trait FooTrait
{
// All broken for static usage.
/**
* This bails but should not.
* @var array<string, T>
*/
private static array $values = [];
/** @param T $arg */
private static function failsButShouldNot($arg): void {}
// All fine for non static usage.
/**
* This works as expected
* @var array<string, T>
*/
private array $values2 = [];
/** @param T $arg */
private function worksAsExpected($arg): void { if ($arg === null); }
}
final readonly class Bar
{
/** @use FooTrait<string> */
use FooTrait;
}
|
I try to design something like this: https://psalm.dev/r/4cf10dedf9
However, as stated by @orklah in #7507 (comment),
Is there a way to design the interface in such a way Psalm won't complain?
The text was updated successfully, but these errors were encountered: