Skip to content

psalm

psalm documentation

psalm - GitHub

Configuration in Mega-Linter

Variable Description Default value
PHP_PSALM_ARGUMENTS User custom arguments to add in linter CLI call
Ex: -s --foo "bar"
PHP_PSALM_FILTER_REGEX_INCLUDE Custom regex including filter
Ex: (src\|lib)
Include every file
PHP_PSALM_FILTER_REGEX_EXCLUDE Custom regex excluding filter
Ex: (test\|examples)
Exclude no file
PHP_PSALM_CLI_LINT_MODE Override default CLI lint mode
- file: Calls the linter for each file
- list_of_files: Call the linter with the list of files as argument
- project: Call the linter from the root of the project
{linter.cli_lint_mode}
PHP_PSALM_FILE_EXTENSIONS Allowed file extensions. "*" matches any extension, "" matches empty extension. Empty list excludes all files
Ex: [".py", ""]
[".php"]
PHP_PSALM_FILE_NAMES_REGEX File name regex filters. Regular expression list for filtering files by their base names using regex full match. Empty list includes all files
Ex: ["Dockerfile(-.+)?", "Jenkinsfile"]
Include every file
PHP_PSALM_PRE_COMMANDS List of bash commands to run before the linter None
PHP_PSALM_POST_COMMANDS List of bash commands to run after the linter None
PHP_PSALM_CONFIG_FILE psalm configuration file name
Use LINTER_DEFAULT to let the linter find it
psalm.xml
PHP_PSALM_RULES_PATH Path where to find linter configuration file Workspace folder, then Mega-Linter default rules
PHP_PSALM_DISABLE_ERRORS Run linter but consider errors as warnings false
PHP_PSALM_DISABLE_ERRORS_IF_LESS_THAN Maximum number of errors allowed 0

IDE Integration

Use psalm in your favorite IDE to catch errors before Mega-Linter !

IDE Extension Name Install
IDEA PHPStan / Psalm / Generics
Visual Studio Code Psalm VsCode Plugin Install in VsCode

Mega-Linter Flavours

This linter is available in the following flavours

Flavor Description Embedded linters Info
all Default Mega-Linter Flavor 94 Docker Image Size (tag) Docker Pulls
php Optimized for PHP based projects 44 Docker Image Size (tag) Docker Pulls

Behind the scenes

How are identified applicable files

  • File extensions: .php

How the linting is performed

  • psalm is called one time by identified file

Example calls

psalm myfile.php
psalm --config=psalm.xml myfile.php

Help content

Usage:
    psalm [options] [file...]

Basic configuration:
    -c, --config=psalm.xml
        Path to a psalm.xml configuration file. Run psalm --init to create one.

    --use-ini-defaults
        Use PHP-provided ini defaults for memory and error display

    --memory-limit=LIMIT
        Use a specific memory limit. Cannot be combined with --use-ini-defaults

    --disable-extension=[extension]
        Used to disable certain extensions while Psalm is running.

    --threads=INT
        If greater than one, Psalm will run analysis on multiple threads, speeding things up.

    --no-diff
        Turns off Psalm’s diff mode, checks all files regardless of whether they’ve changed.

Surfacing issues:
    --show-info[=BOOLEAN]
        Show non-exception parser findings (defaults to false).

    --show-snippet[=true]
        Show code snippets with errors. Options are 'true' or 'false'

    --find-dead-code[=auto]
    --find-unused-code[=auto]
        Look for unused code. Options are 'auto' or 'always'. If no value is specified, default is 'auto'

    --find-unused-psalm-suppress
        Finds all @psalm-suppress annotations that aren’t used

    --find-references-to=[class|method|property]
        Searches the codebase for references to the given fully-qualified class or method,
        where method is in the format class::methodName

    --no-suggestions
        Hide suggestions

    --taint-analysis
        Run Psalm in taint analysis mode – see https://psalm.dev/docs/security_analysis for more info

    --dump-taint-graph=OUTPUT_PATH
        Output the taint graph using the DOT language – requires --taint-analysis

Issue baselines:
    --set-baseline=PATH
        Save all current error level issues to a file, to mark them as info in subsequent runs

        Add --include-php-versions to also include a list of PHP extension versions

    --use-baseline=PATH
        Allows you to use a baseline other than the default baseline provided in your config

    --ignore-baseline
        Ignore the error baseline

    --update-baseline
        Update the baseline by removing fixed issues. This will not add new issues to the baseline

        Add --include-php-versions to also include a list of PHP extension versions

Plugins:
    --plugin=PATH
        Executes a plugin, an alternative to using the Psalm config

Output:
    -m, --monochrome
        Enable monochrome output

    --output-format=console
        Changes the output format.
        Available formats: compact, console, text, emacs, json, pylint, xml, checkstyle, junit, sonarqube, github,
                           phpstorm, codeclimate

    --no-progress
        Disable the progress indicator

    --long-progress
        Use a progress indicator suitable for Continuous Integration logs

    --stats
        Shows a breakdown of Psalm’s ability to infer types in the codebase

Reports:
    --report=PATH
        The path where to output report file. The output format is based on the file extension.
        (Currently supported formats: ".json", ".xml", ".txt", ".emacs", ".pylint", ".console",
        ".sarif", "checkstyle.xml", "sonarqube.json", "codeclimate.json", "summary.json", "junit.xml")

    --report-show-info[=BOOLEAN]
        Whether the report should include non-errors in its output (defaults to true)

Caching:
    --clear-cache
        Clears all cache files that Psalm uses for this specific project

    --clear-global-cache
        Clears all cache files that Psalm uses for all projects

    --no-cache
        Runs Psalm without using cache

    --no-reflection-cache
        Runs Psalm without using cached representations of unchanged classes and files.
        Useful if you want the afterClassLikeVisit plugin hook to run every time you visit a file.

    --no-file-cache
        Runs Psalm without using caching every single file for later diffing.
        This reduces the space Psalm uses on disk and file I/O.

Miscellaneous:
    -h, --help
        Display this help message

    -v, --version
        Display the Psalm version

    -i, --init [source_dir=src] [level=3]
        Create a psalm config file in the current directory that points to [source_dir]
        at the required level, from 1, most strict, to 8, most permissive.

    --debug
        Debug information

    --debug-by-line
        Debug information on a line-by-line level

    --debug-emitted-issues
        Print a php backtrace to stderr when emitting issues.

    -r, --root
        If running Psalm globally you’ll need to specify a project root. Defaults to cwd

    --generate-json-map=PATH
        Generate a map of node references and types in JSON format, saved to the given path.

    --generate-stubs=PATH
        Generate stubs for the project and dump the file in the given path

    --shepherd[=host]
        Send data to Shepherd, Psalm’s GitHub integration tool.

    --alter
        Run Psalter

    --language-server
        Run Psalm Language Server

Installation on mega-linter Docker image

  • Dockerfile commands :
# Parent descriptor install
RUN wget --tries=5 -q -O phive.phar https://phar.io/releases/phive.phar \
    && wget --tries=5 -q -O phive.phar.asc https://phar.io/releases/phive.phar.asc \
    && PHAR_KEY_ID="0x9D8A98B29B2D5D79" \
    && ( gpg --keyserver keyserver.pgp.com --recv-keys "$PHAR_KEY_ID" \
        || gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$PHAR_KEY_ID" \
        || gpg --keyserver pgp.mit.edu --recv-keys "$PHAR_KEY_ID" \
        || gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys "$PHAR_KEY_ID" ) \
    && gpg --verify phive.phar.asc phive.phar \
    && chmod +x phive.phar \
    && mv phive.phar /usr/local/bin/phive \
    && rm phive.phar.asc

# Linter install
RUN phive --no-progress install psalm -g --trust-gpg-keys 8A03EA3B385DBAA1,12CE0F1D262429A5

Example success log

Results of psalm linter (version 4.3.1)
See documentation on https://megalinter.github.io/descriptors/php_psalm/
-----------------------------------------------

[SUCCESS] .automation/test/php/php_good_1.php
    Scanning files...
    Analyzing files...

    ░
    ------------------------------
    No errors found!
    ------------------------------

    Checks took 0.25 seconds and used 39.379MB of memory
    Psalm was unable to infer types in the codebase

[SUCCESS] .automation/test/php/php_good_2.php
    Scanning files...
    Analyzing files...

    ░
    ------------------------------
    No errors found!
    ------------------------------

    Checks took 0.31 seconds and used 36.996MB of memory
    Psalm was unable to infer types in the codebase

Example error log

Results of psalm linter (version 4.3.1)
See documentation on https://megalinter.github.io/descriptors/php_psalm/
-----------------------------------------------

[ERROR] .automation/test/php/php_bad_1.php
    Scanning files...
    Analyzing files...

    E

    ERROR: ParseError - ../../...automation/test/php/php_bad_1.php:3:2 - Syntax error, unexpected T_STRING on line 3 (see https://psalm.dev/173)
    2pe98y r-n0u823n=r  092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr  298yr3  29


    ERROR: UndefinedConstant - ../../...automation/test/php/php_bad_1.php:3:2 - Const pe98y is not defined (see https://psalm.dev/020)
    2pe98y r-n0u823n=r  092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr  298yr3  29


    ERROR: UndefinedConstant - ../../...automation/test/php/php_bad_1.php:3:8 - Const r is not defined (see https://psalm.dev/020)
    2pe98y r-n0u823n=r  092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr  298yr3  29


    ERROR: UndefinedConstant - ../../...automation/test/php/php_bad_1.php:3:10 - Const n0u823n is not defined (see https://psalm.dev/020)
    2pe98y r-n0u823n=r  092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr  298yr3  29


    ERROR: ParseError - ../../...automation/test/php/php_bad_1.php:3:17 - Syntax error, unexpected '=' on line 3 (see https://psalm.dev/173)
    2pe98y r-n0u823n=r  092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr  298yr3  29


    ERROR: UndefinedConstant - ../../...automation/test/php/php_bad_1.php:3:18 - Const r is not defined (see https://psalm.dev/020)
    2pe98y r-n0u823n=r  092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr  298yr3  29


    ERROR: ParseError - ../../...automation/test/php/php_bad_1.php:3:21 - Invalid numeric literal on line 3 (see https://psalm.dev/173)
    2pe98y r-n0u823n=r  092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr  298yr3  29


    ERROR: UndefinedConstant - ../../...automation/test/php/php_bad_1.php:3:24 - Const u3 is not defined (see https://psalm.dev/020)
    2pe98y r-n0u823n=r  092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr  298yr3  29


    ERROR: UndefinedConstant - ../../...automation/test/php/php_bad_1.php:3:28 - Const r08u2q098ry is not defined (see https://psalm.dev/020)
    2pe98y r-n0u823n=r  092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr  298yr3  29


    ERROR: ParseError - ../../...automation/test/php/php_bad_1.php:3:40 - Syntax error, unexpected T_LNUMBER on line 3 (see https://psalm.dev/173)
    2pe98y r-n0u823n=r  092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr  298yr3  29


    ERROR: UndefinedConstant - ../../...automation/test/php/php_bad_1.php:3:42 - Const nq2yr09n2yr9 is not defined (see https://psalm.dev/020)
    2pe98y r-n0u823n=r  092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr  298yr3  29


    ERROR: UndefinedConstant - ../../...automation/test/php/php_bad_1.php:3:55 - Const y2n is not defined (see https://psalm.dev/020)
    2pe98y r-n0u823n=r  092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr  298yr3  29


    ERROR: ParseError - ../../...automation/test/php/php_bad_1.php:3:61 - Syntax error, unexpected T_STRING on line 3 (see https://psalm.dev/173)
    2pe98y r-n0u823n=r  092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr  298yr3  29


    ERROR: UndefinedConstant - ../../...automation/test/php/php_bad_1.php:3:61 - Const yr is not defined (see https://psalm.dev/020)
    2pe98y r-n0u823n=r  092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr  298yr3  29


    ERROR: UndefinedConstant - ../../...automation/test/php/php_bad_1.php:3:68 - Const yr3 is not defined (see https://psalm.dev/020)
    2pe98y r-n0u823n=r  092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr  298yr3  29


    ------------------------------
    15 errors found
    ------------------------------

    Checks took 0.30 seconds and used 39.560MB of memory
    Psalm was unable to infer types in the codebase

[ERROR] .automation/test/php/php_bad_2.php
    Scanning files...
    Analyzing files...

    E

    ERROR: InvalidReturnType - ../../...automation/test/php/php_bad_2.php:4:12 - The declared return type 'array<array-key, string>' for takesAnInt is incorrect, got 'array{int, string(hello)}' (see https://psalm.dev/011)
     * @return array<string>


    ERROR: InvalidReturnStatement - ../../...automation/test/php/php_bad_2.php:7:12 - The inferred type 'array{int, string(hello)}' does not match the declared return type 'array<array-key, string>' for takesAnInt (see https://psalm.dev/128)
        return [$i, "hello"];


    ERROR: InvalidScalarArgument - ../../...automation/test/php/php_bad_2.php:11:12 - Argument 1 of takesAnInt expects int, string(some text) provided (see https://psalm.dev/012)
    takesAnInt($data[0]);


    ERROR: ParseError - ../../...automation/test/php/php_bad_2.php:15:1 - Syntax error, unexpected '}' on line 15 (see https://psalm.dev/173)
    } elseif ($condition) {}


    ------------------------------
    4 errors found
    ------------------------------
    Psalm can automatically fix 1 of these issues.
    Run Psalm again with 
    --alter --issues=InvalidReturnType --dry-run
    to see what it can fix.
    ------------------------------

    Checks took 0.32 seconds and used 36.047MB of memory
    Psalm was unable to infer types in the codebase