vimeo/psalm
Psalm is a static analysis tool for PHP that finds type errors, bugs, and unsafe code before runtime. It offers configurable strictness, baseline support, and CI integration to help teams catch issues early and improve code quality.
Architecture fit
require-dev). It ships no runtime code path, so there is zero impact on Laravel's bootstrap, container, autoload graph, or production artifact size. Architecture review is correspondingly cheap compared to a runtime library.$_SERVER and $_FILES entries, DNS answers, paths/URLs consumed by builtins, and exception messages caught across @throws propagation.printf/vprintf/print_r/var_dump/var_export/debug_zval_dump/vfprintf/gzpassthru/highlight_file/highlight_string and writes to php://output / php://stdout, i.e. the HTTP response body.__toString, implode/join, and array element write/unset tracking; superglobals are invalidated after calls that may write globals, and $_SESSION is reset after session_unset().php://output writes) that Laravel teams historically considered harmless.Integration feasibility
composer require --dev vimeo/psalm, MIT license — no legal or procurement friction.psalm-plugin-laravel package (facades, Eloquent magic properties, container resolution, validation). This plugin, not Psalm itself, is the real feasibility gate — and with rc2 it is now also the gate on whether the new sink and $_SERVER behaviour is usable inside framework code.--set-baseline) remain the decisive unlock for brownfield adoption. rc2 raises the stakes: the taint job should have a separate baseline from the type-analysis baseline, because the new sinks and $_SERVER sources generate a distinct class of finding that does not belong in a type-error baseline and will churn independently.--init auto-selects an error level matching the current error count, giving a sane starting strictness without manual tuning.Technical risk
print_r, var_dump, debug_zval_dump, and writes to php://output are common in Laravel debug paths and Blade templates. Security-correct to flag, but expect a loud first run. Mitigate by shipping the taint job report-only and triaging the sink policy explicitly.$_SERVER / $_FILES tainting intersects with Laravel's request path. Framework internals read REQUEST_URI, HTTP_HOST, and similar. Expect a spike of findings in framework-adjacent code. This is a "verify before trusting" area, not a "disable the tool" area.$_SESSION, list/array writes, and exception messages are now tracked. Confidence in taint as a control goes up; it is still not a security guarantee.psalm-plugin-laravel, blocking upgrades on unrelated PRs. rc2 does not change this; it makes the plugin compatibility check more consequential because the new sinks are the value proposition.Key questions
Dom\ stubs on the 6.x line.)print_r, var_dump, debug_zval_dump, php://output / php://stdout writes)? Suppress project-wide in the initial taint baseline, or triage case-by-case?$_SERVER / $_FILES taint findings surfacing through framework request internals — plugin-side suppression, per-directory exclusion, or vendor-ignore?Stack fit
Dom\ stubs; verify the runtime matrix against whichever major we adopt.Migration path Baseline-first, five steps:
psalm --init to auto-pick an error level.psalm-baseline.xml for the type job to freeze existing debt — the gate is green on day one.--taint-analysis as a separate, initially non-blocking CI job with its own baseline. It is noisier and slower than type analysis and should not share a gate with it. In rc2, seed the taint baseline only after the var_dump/print_r/php://output and $_SERVER questions are answered.Compatibility
^6.0 or ^7.0) and pin psalm-plugin-laravel to a compatible major; group both in a single Dependabot/Renovate PR so upgrades are deliberate and reviewable.psalm.xml, type baseline, taint baseline, and any custom stubs as reviewed source.@psalm-* annotations, to keep a future migration to PHPStan mechanical.Sequencing
$_SERVER sources. This single data point decides the programme.Maintenance
Support
Scaling
--threads, the incremental cache, and changed-files-only runs for PR fast lanes; full nightly analysis for the authoritative gate.psalm.xml with project references, or scope PR analysis to changed paths.Failure modes
@psalm-suppress with mandatory justification comments and a documented triage SLA.var_dump/print_r/php://output findings in debug code and Blade. Mitigation: separate non-blocking taint job, explicit sink policy decision (question 9), seed baseline after policy is set.$_SERVER / $_FILES tainting produces a wall of findings in Laravel request internals. Mitigation: verify against psalm-plugin-laravel, per-directory or vendor exclusion, escalate to the maintainer if the plugin does not model Request correctly.--memory-limit, sharding, nightly full runs, split type and taint jobs.Ramp-up
@template, purity/@psalm-immutable, and taint annotations. The binding constraint is triage discipline, not tool knowledge.How can I help you explore Laravel packages today?