Upgrading to Psalm 7
For most projects, upgrading is as simple as updating the Composer dependency:
composer require --dev vimeo/psalm:^7.0 -W
-W lets Composer also upgrade Psalm's own dependencies that your lock file pins to older versions (for example amphp/parallel or nikic/php-parser); without it Composer refuses the update. If your composer.json requires psalm/plugin-phpunit, add psalm/plugin-phpunit:^0.21 to the same command.
--set-baseline writes a fresh baseline. --update-baseline isn't enough here: it only removes fixed entries and doesn't add new ones.
The rest of this page covers what some projects will notice. The complete list of breaking changes, mostly relevant to plugin authors, is in UPGRADING.md.
What you may notice
- Taint analysis runs by default, in the same run as type checking, and is faster than a separate
--taint-analysisrun (see the release notes). To run type checking only, setrunTaintAnalysis="false". - New security findings. If taint analysis reports more than you want to deal with at once, you have these tools (docs):
@psalm-cli-onlyon a function, method or class: what its code prints is not reported asTaintedHtml;<taintAnalysis><ignoreFiles>inpsalm.xml: taint paths through the listed files and directories (tests, for example) are not reported;@psalm-taint-specialize: each call of a function or each instance of a class is tracked separately;runTaintAnalysis="false": turn it off.
- Baselines: regenerate yours with
--set-baseline=psalm-baseline.xmlafter upgrading (--update-baselineonly removes fixed entries, it doesn't add new ones). Some issues are now reported at a different position (for exampleImpureMethodCall), and baseline entries that are no longer used are reported asUnusedBaselineEntry. - Purity annotation suggestions are optional.
MissingPureAnnotation,MissingImmutableAnnotation,MissingAbstractPureAnnotationandMissingInterfaceImmutableAnnotationare only reported with<psalm suggestPurityAnnotations="true">(they are off by default), and--alter --issues=MissingPureAnnotation,MissingImmutableAnnotationworks without it. If your baseline contains these issues, set the attribute or run--update-baseline. Annotating is still worth it, for three reasons:- Fewer security false positives: Psalm specializes the taints of calls to pure and read-only functions and methods per call site. Tainted input passed at one call then no longer taints the result of every other call. Without annotations, Psalm can only infer this for functions and methods that can't be overridden.
- Better type inference: Psalm remembers the results of methods of immutable classes between calls, so
$a->get() !== null ? $a->get() : ''is astring. Without@psalm-immutable, for a class that can be extended, the second call is still?string. - Checked contracts: pure code can call the annotated functions, and every override and implementation is checked not to do more than the annotation allows.
- Purity annotations:
@psalm-mutation-freeand@psalm-external-mutation-freeare still accepted, but Psalm now suggests@psalm-capabilities. Theself-accessing-*andself-mutating-*callable types are removed,@psalm-purity-from $paramis replaced by purity templates, and purity arguments go in square brackets (Traversable[pure]<int, string>). - Dead code in libraries: graph-based detection also reports code used only by other unused code, cycles included. Mark entry points and public API with
@psalm-api(or@api). --output-format=compactnow selects the new compact format. Usetablefor the old output.- PHP 8.1 and 32-bit PHP are no longer supported for running Psalm. Code targeting older PHP versions can still be analysed.
psalm/plugin-phpunit: Psalm 7 requires^0.21. Projects that pin^0.19or^0.20must raise the constraint.- Docker: use the official image,
ghcr.io/psalm/psalm. - Plugins: taints are integers (
TaintKindbitmask) in the plugin API.TKeyedArrayis built withTKeyedArray::make(). SeveralCodebasemethods take aContext. Plugins must requirepsalm/psalm-plugin-api(^0.4), because from now on a Psalm minor or patch release may break the plugin API (see psalm/psalm-plugin-api).