jiripudil / phpstan-sealed-classes
Sealed classes support for PHPStan.
Fund package maintenance!
jiripudil
Installs: 71 384
Dependents: 2
Suggesters: 0
Security: 0
Stars: 32
Watchers: 5
Forks: 0
Open Issues: 1
Type:phpstan-extension
Requires
- php: ^8.1
- phpstan/phpstan: ^2.0
Requires (Dev)
- php-parallel-lint/php-parallel-lint: ^1.4
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^10.5 || ^11.4
README
This extension adds support for sealed classes and interfaces to PHPStan.
Installation
To use this extension, require it via Composer
composer require --dev jiripudil/phpstan-sealed-classes
If you are using phpstan/extension-installer
, this extension's configuration will be automatically enabled.
Otherwise, you need to include it explicitly in your phpstan.neon
:
includes: - vendor/jiripudil/phpstan-sealed-classes/extension.neon
Usage
Sealed classes and interfaces allow developers to restrict class hierarchies: a sealed class can only be subclassed by classes that are explicitly permitted to do so. The same applies to sealed interfaces and their implementations. In a way, sealed classes are similar to enumerations, with an important distinction: while enums are singletons, a subclass of a sealed class can have multiple instances, each with its own state.
You can seal a class or an interface by attributing it as #[Sealed]
. The attribute accepts a list of permitted descendants or implementations:
<?php use JiriPudil\SealedClasses\Sealed; #[Sealed(permits: [AllowedImplementation::class, AnotherImplementation::class])] interface SealedInterface {} class AllowedImplementation implements SealedInterface {} class AnotherImplementation implements SealedInterface {} class DisallowedImplementation implements SealedInterface {}
While the first two classes will be allowed, PHPStan will report an error for the third:
------ ----------------------------------------------------------------------------------
Line sealed-interface.php
------ ----------------------------------------------------------------------------------
10 Type DisallowedImplementation is not allowed to be a subtype of SealedInterface.
------ ----------------------------------------------------------------------------------
Note that the restrictions do not apply to indirect subclasses. If a direct subclass of a sealed class is not sealed itself, it can be further extended without raising any errors. This code is perfectly fine:
<?php use JiriPudil\SealedClasses\Sealed; #[Sealed(permits: [AllowedDescendant::class])] abstract class SealedClass {} class AllowedDescendant extends SealedClass {} class IndirectDescendant extends AllowedDescendant {}