dave-liddament/phpstan-php-language-extensions
A PHPStan extension that adds support for extra PHP language features and type declarations, widening static analysis coverage so PHPStan understands more of your code. Helps catch bugs earlier and reduces false positives in Laravel and PHP projects.
This extension wires the attributes from dave-liddament/php-language-extensions into PHPStan, so violations of those attributes become static-analysis errors instead of runtime surprises.
Install the runtime attributes package and the PHPStan rule package (the latter is dev-only because it only matters during analysis):
composer require dave-liddament/php-language-extensions
composer require --dev dave-liddament/phpstan-php-language-extensions
Register the rules. If you use phpstan/extension-installer, they are picked up automatically. Otherwise include the shipped ruleset in phpstan.neon:
includes:
- vendor/dave-liddament/phpstan-php-language-extensions/rules.neon
Look first at your existing phpstan.neon and the package's rules.neon / README to see which rules are registered and which parameters keys they read. The attributes are inert at runtime, so nothing changes behavior — analysis is where they pay off.
First use case: mark an unstable class as #[Internal] and confirm PHPStan flags a call from outside the allowed namespace. That single rule is the one most teams adopt first, because it turns "please don't use this" comments into build failures.
#[Internal] / #[NotInternal]). Tag implementation classes as internal; the rule reports usage from outside the package/namespace you configure. Use #[NotInternal] on the few classes that must stay public (e.g. a factory you re-export).#[RequiresNamedArguments]). Put it on constructors and factory methods whose signatures are likely to change. The rule flags positional calls, so adding a parameter later doesn't silently reorder arguments at call sites.#[EnforceReadonly]). Apply to value objects; the rule insists the class and its properties are readonly, catching classes that drifted from the convention.phpstan --generate-baseline), then fix incrementally.vendor/bin/phpstan analyse step — no new CI job required. Add the analysis target for src/ only; you generally don't want to analyze vendor attributes themselves.#[Internal], also mark the method @internal in the docblock so IDE/other tooling aligns with the PHPStan rule.identifier (something like phpLanguageExtensions.internal) in ignoreErrors rather than the message text, which can vary between PHPStan versions.Internal are the thing most likely to change. Pin a version in composer.json and check the README on upgrade.EnforceReadonly can false-positive. Classes that legitimately need mutable state will trip it. Prefer removing the attribute over suppressing; suppression is a slippery slope here.call_user_func, variable functions, new $class) escape it — don't assume full coverage.#[Internal] requires autoloading during analysis. If the class isn't autoloadable at PHPStan time (odd PSR-4 setups, generated code), the rule can't read the attribute and silently passes. Verify with phpstan -vvv that the file is being resolved.@internal and vice versa. The attribute drives PHPStan; the docblock drives IDEs and other static analyzers. For a public surface you care about, set both.ignoreErrors list.How can I help you explore Laravel packages today?