diff --git a/psalm.xml b/psalm.xml index ff3a11d..dc8bf39 100644 --- a/psalm.xml +++ b/psalm.xml @@ -9,6 +9,7 @@ + diff --git a/src/Doctrine/PlatenumDoctrineType.php b/src/Doctrine/PlatenumDoctrineType.php index fc990fc..b07554f 100644 --- a/src/Doctrine/PlatenumDoctrineType.php +++ b/src/Doctrine/PlatenumDoctrineType.php @@ -6,7 +6,10 @@ use Doctrine\DBAL\Types\Type; use Thunder\Platenum\Enum\EnumTrait; -/** @psalm-suppress PropertyNotSetInConstructor, MissingConstructor */ +/** + * @psalm-suppress PropertyNotSetInConstructor, MissingConstructor + * @psalm-external-mutation-free + */ final class PlatenumDoctrineType extends Type { /** @var class-string */ diff --git a/src/Enum/AbstractCallbackEnum.php b/src/Enum/AbstractCallbackEnum.php index 49d812f..6543a16 100644 --- a/src/Enum/AbstractCallbackEnum.php +++ b/src/Enum/AbstractCallbackEnum.php @@ -4,8 +4,11 @@ /** * @author Tomasz Kowalczyk + * @psalm-template T + * @psalm-immutable */ abstract class AbstractCallbackEnum implements \JsonSerializable { + /** @use CallbackEnumTrait */ use CallbackEnumTrait; } diff --git a/src/Enum/AbstractConstantsEnum.php b/src/Enum/AbstractConstantsEnum.php index 696b0d6..cb3faf4 100644 --- a/src/Enum/AbstractConstantsEnum.php +++ b/src/Enum/AbstractConstantsEnum.php @@ -4,8 +4,11 @@ /** * @author Tomasz Kowalczyk + * @psalm-template T + * @psalm-immutable */ abstract class AbstractConstantsEnum implements \JsonSerializable { + /** @use ConstantsEnumTrait */ use ConstantsEnumTrait; } diff --git a/src/Enum/AbstractDocblockEnum.php b/src/Enum/AbstractDocblockEnum.php index d7d994c..2ae7bc8 100644 --- a/src/Enum/AbstractDocblockEnum.php +++ b/src/Enum/AbstractDocblockEnum.php @@ -4,8 +4,11 @@ /** * @author Tomasz Kowalczyk + * @psalm-template T + * @psalm-immutable */ abstract class AbstractDocblockEnum implements \JsonSerializable { + /** @use DocblockEnumTrait */ use DocblockEnumTrait; } diff --git a/src/Enum/AbstractStaticEnum.php b/src/Enum/AbstractStaticEnum.php index 6f347fa..fb16bb2 100644 --- a/src/Enum/AbstractStaticEnum.php +++ b/src/Enum/AbstractStaticEnum.php @@ -4,9 +4,12 @@ /** * @author Tomasz Kowalczyk + * @psalm-template T + * @psalm-immutable */ abstract class AbstractStaticEnum implements \JsonSerializable { + /** @use StaticEnumTrait */ use StaticEnumTrait; /** @var array */ diff --git a/src/Enum/CallbackEnumTrait.php b/src/Enum/CallbackEnumTrait.php index 6c8b773..a45cf07 100644 --- a/src/Enum/CallbackEnumTrait.php +++ b/src/Enum/CallbackEnumTrait.php @@ -6,9 +6,12 @@ /** * @author Tomasz Kowalczyk + * @psalm-template T + * @psalm-immutable */ trait CallbackEnumTrait { + /** @use EnumTrait */ use EnumTrait; /** @var non-empty-array> */ diff --git a/src/Enum/ConstantsEnumTrait.php b/src/Enum/ConstantsEnumTrait.php index 4a1aea5..4930e1f 100644 --- a/src/Enum/ConstantsEnumTrait.php +++ b/src/Enum/ConstantsEnumTrait.php @@ -4,9 +4,12 @@ /** * @author Tomasz Kowalczyk + * @psalm-template T + * @psalm-immutable */ trait ConstantsEnumTrait { + /** @use EnumTrait */ use EnumTrait; private static function resolve(): array diff --git a/src/Enum/DocblockEnumTrait.php b/src/Enum/DocblockEnumTrait.php index 0784a7d..5bf71b4 100644 --- a/src/Enum/DocblockEnumTrait.php +++ b/src/Enum/DocblockEnumTrait.php @@ -6,9 +6,12 @@ /** * @author Tomasz Kowalczyk + * @psalm-template T + * @psalm-immutable */ trait DocblockEnumTrait { + /** @use EnumTrait */ use EnumTrait; private static function resolve(): array diff --git a/src/Enum/EnumTrait.php b/src/Enum/EnumTrait.php index edb9d2b..d183569 100644 --- a/src/Enum/EnumTrait.php +++ b/src/Enum/EnumTrait.php @@ -6,20 +6,22 @@ /** * @author Tomasz Kowalczyk + * @psalm-template T + * @psalm-immutable */ trait EnumTrait { /** @var string */ private $member; - /** @var int|string */ + /** @psalm-var T */ private $value; - /** @var non-empty-array> */ + /** @psalm-var non-empty-array> */ protected static $members = []; /** @var array> */ protected static $instances = []; - /** @param int|string $value */ + /** @psalm-param T $value */ final private function __construct(string $member, $value) { $this->member = $member; @@ -51,8 +53,17 @@ final public static function fromMember(string $member): self static::throwDefaultInvalidMemberException($member); } + return static::$instances[$class][$member] = static::fromMemberAndValue($member, static::$members[$class][$member]); + } + + /** + * @psalm-param int|string $value + * @psalm-return static + */ + final private static function fromMemberAndValue(string $member, $value): self + { /** @psalm-suppress UnsafeInstantiation */ - return static::$instances[$class][$member] = new static($member, static::$members[$class][$member]); + return new static($member, $value); } /** @@ -91,8 +102,8 @@ final public static function fromEnum($enum): self } /** - * @param static $enum - * @param-out AbstractConstantsEnum|AbstractDocblockEnum|AbstractStaticEnum|AbstractCallbackEnum|AbstractAttributeEnum $enum + * @param self &$enum + * @param-out self $enum */ final public function fromInstance(&$enum): void { @@ -140,12 +151,13 @@ final public function getMember(): string return $this->member; } - /** @return int|string */ + /** @psalm-return T */ final public function getValue() { return $this->value; } + /** @psalm-return T */ #[\ReturnTypeWillChange] final public function jsonSerialize() { @@ -179,7 +191,7 @@ final public function hasMember(string $members): bool return $members === $this->member; } - /** @param int|string $value */ + /** @psalm-param T $value */ final public function hasValue($value): bool { return $value === $this->value; @@ -245,7 +257,7 @@ private static function resolveMembers(): void // reflection instead of method_exists because of PHP 7.4 bug #78632 // @see https://bugs.php.net/bug.php?id=78632 $hasResolve = (new \ReflectionClass($class))->hasMethod('resolve'); - /** @var array $members */ + /** @psalm-var array $members */ $members = $hasResolve ? static::resolve() : $throwMissingResolve($class); if(empty($members)) { throw PlatenumException::fromEmptyMembers($class); diff --git a/src/Enum/StaticEnumTrait.php b/src/Enum/StaticEnumTrait.php index 738cee2..01a54eb 100644 --- a/src/Enum/StaticEnumTrait.php +++ b/src/Enum/StaticEnumTrait.php @@ -6,9 +6,12 @@ /** * @author Tomasz Kowalczyk + * @psalm-template T + * @psalm-immutable */ trait StaticEnumTrait { + /** @use EnumTrait */ use EnumTrait; private static function resolve(): array diff --git a/tests/Psalm/PsalmEnum.php b/tests/Psalm/PsalmEnum.php new file mode 100644 index 0000000..e5d26d8 --- /dev/null +++ b/tests/Psalm/PsalmEnum.php @@ -0,0 +1,47 @@ + */ + use ConstantsEnumTrait; + + public const FIRST = 1; + public const SECOND = 2; +} + +PsalmConstantsTraitEnum::FIRST(); +PsalmConstantsTraitEnum::SECOND(); +PsalmConstantsTraitEnum::fromMember('THIRD'); +PsalmConstantsTraitEnum::fromValue(4); + +/** + * @method static static FIRST() + * @method static static SECOND() + * @psalm-template T of self::* + * @psalm-immutable + */ +final class PsalmConstantsExtendsEnum extends AbstractConstantsEnum +{ + public const FIRST = 1; + public const SECOND = 2; +} + +PsalmConstantsExtendsEnum::FIRST(); +PsalmConstantsExtendsEnum::SECOND(); +PsalmConstantsExtendsEnum::fromMember('THIRD'); +PsalmConstantsExtendsEnum::fromValue(4); \ No newline at end of file