phpstan/phpstan-deprecation-rules
PHPStan extension that reports usage of deprecated classes, methods, properties, constants, and traits. Supports custom deprecation markers and scopes, with stub files for deprecations in third-party code you don’t own.
Architecture fit. phpstan/phpstan-deprecation-rules is not a runtime library — it is a ruleset extension for PHPStan that adds detection of @deprecated symbols (classes, methods, properties, constants, traits). For a Laravel codebase it slots in one layer above Larastan, which is already the de‑facto static analysis adapter for the framework. The fit is clean: no application code changes, no service provider, no runtime overhead. It is a require-dev dependency that activates via phpstan/extension-installer or a single includes: entry in phpstan.neon. From a TPM perspective this is an unusually low-friction capability: the value is realized as information, not as an integration surface.
The genuinely differentiating features — and the ones worth planning around — are the three extension points, not the base rules:
@deprecated on vendor code we don't own (third‑party packages that never annotated their APIs).#[Deprecated] attribute or docblock convention is recognized, giving us a single deprecation vocabulary across first‑ and third‑party code.DeprecatedScopeResolver to suppress reporting inside intentionally-deprecated scopes, which is exactly the mechanism needed for a legacy adapter/facade layer during a major upgrade.Integration feasibility. High. Installation is a two‑line change and the README documents both the installer and manual (rules.neon) paths. The real constraint is version alignment: the 2.0.x line targets PHPStan 2.x, which in turn constrains the Larastan major. Older Laravel estates pinned to PHPStan 1.x must stay on the 1.1.x rules line. This is a compatibility matrix problem, not an engineering problem, and should be settled before any rollout commitment.
Technical risk.
RestrictedMethodUsageExtension, RestrictedClassNameUsageExtension, etc.) and removed UsageOfDeprecatedCastRule as redundant. Rule identifiers can therefore change between minors, which invalidates baselines and ignoreErrors entries. Any "we'll just bump the patch version" assumption is unsafe.Cache::get(), DB::table()), container resolution, macros, Blade templates, and string-based invocations are not statically resolvable to a declared deprecated member, so they will not be flagged. The tool will systematically under-report exactly where Laravel code is most dynamic. This must be communicated so the metric isn't over-trusted.Key questions.
Stack fit. Composer require-dev; activated through phpstan/extension-installer (preferred, zero config) or an explicit includes: line in phpstan.neon/phpstan.neon.dist. It must be co-versioned with phpstan/phpstan and larastan/larastan in CI and in the local dev image so developers and pipelines report identically. No changes to composer.json autoload, no Laravel provider, no environment configuration.
Migration path.
composer.lock; document the supported matrix in the repo README.app/, domain/, packages/), explicitly excluding vendor/, storage/, bootstrap/cache/, and generated code.phpstan-baseline.neon to freeze existing deprecation debt. This is the single most important step: it converts an unbounded backlog into a tracked burndown and prevents day-one CI failure.#[Deprecated] attribute support) so our own service layer participates in the same reporting pipeline.DeprecatedScopeResolver to whitelist the legacy adapter layer so it doesn't generate permanent noise while it exists.Compatibility. Two hard seams: PHPStan 2.x is required for the 2.0.x rules line, and PHPStan majors gate Larastan majors, which gate supported Laravel versions. For a mixed estate, the pragmatic answer is to standardize on one PHPStan major across applications before adopting, rather than maintaining parallel rulesets. Also account for PHP-version-conditional deprecations (Scope->getPhpVersion() behavior, per 2.0.4) — the reported set changes if CI and local PHP targets differ.
Sequencing. Land the ruleset in a single reference application with baseline + report-only CI job first, measure volume and false-positive rate over two sprints, then template the config out. Do not attempt an estate-wide blocking gate in the first pass; the baseline churn from a coupled version bump is the most likely cause of a rollback.
Maintenance. Low surface area, non-trivial cadence. The extension is a thin ruleset, but it is version-locked to PHPStan core and its releases frequently include rule relocation into core. Budget for a dependency-bump ticket per PHPStan major and occasional minor (rule identifier migrations), each requiring baseline regeneration and a diff review. Assign a named owner for static analysis configuration — this package should not be an unowned require-dev line.
Support. Upstream is a single-maintainer-dominated ecosystem (PHPStan) with fast, terse triage and frequent releases. There is no commercial support tier. Internal support burden is limited to "why is this line red?" questions, which resolve to the baseline/ignore workflow. Document the three suppression mechanisms (@deprecated scope, baseline, DeprecatedScopeResolver) so engineers don't reach for blanket ignoreErrors.
Scaling. PHPStan cost scales with analyzed file count and level; the deprecation ruleset adds a marginal constant on top rather than changing the complexity class. On large Laravel monorepos the practical limits are memory and wall time — configure memory-limit, parallel workers, and result cache, and scope analysis to owned paths. Expect the CI job to need its own budget line before it is promoted to blocking.
Failure modes.
E_DEPRECATED capture in staging) and a grep-based facade-usage audit for the specific APIs being removed.phpVersion targets differ between configs — pin it explicitly.Ramp-up. Effectively zero for consumers — the value appears in existing PHPStan output. The learning investment is in policy, not tooling: how we baseline, how we suppress deliberately, how we treat vendor gaps. One short internal write-up plus the reference-app example is sufficient. Expect the first two weeks of output to be dominated by pre-existing framework deprecations; that initial list is itself a useful deliverable for planning the next Laravel/PHP upgrade, and should be sized and socialized rather than quietly baselined.
How can I help you explore Laravel packages today?