Why you should use Psalm for PHP

What is Psalm:

Psalm is a type-checking static analysis tool for PHP that finds bugs humans can miss and improves code quality. It is designed to be useful on both large legacy codebases and small modern ones. It can help you prevent the vast majority of type-related runtime errors and also enables you to take advantage of safe coding patterns popular in other languages.

Some people might insinuate that “PSALM” refers to something religious, but in fact, it’s short for PHP Static Analysis Linting Machine (PSALM).

Why Psalm is important:

One of the main reasons developers get more stressed while extending or debugging code is a lack of type-hinting on many properties, methods, or functions. While this code works initially, as our applications mature and our codebase grows, more clarity is needed to maintain our code, leading to more regressions and unstable services.

In addition:

  • You might need to add more and more test cases to cover all types.
  • Your codebase might be confusing for new developers.
  • Your codebase might be unreadable or unmaintainable.
  • You may face the appearance of unexpected errors.

Introducing a static analysis tool, such as Psalm, can be very helpful in tackling those problems.

What Psalm can do:

  • Detect type errors
  • Detect dead code
  • Detect usages of unknown classes
  • Fix some detected bugs auto
  • And more

How Psalm works:

When using Psalm, you have to take into consideration two main parameters. Error levels and code issues.

Errors levels:
  • Psalm has different levels of strictness from 1 to 8.
  • Level 1 is the strictest.
  • Level 8 is the most lenient.
  • The default error level is 2.
  • Treating errors based on level.
Code issues:
  • error — This will cause Psalm to print a message, and ultimately terminate with a non-zero exit status.
  • info — This will cause Psalm to print a message.
  • suppress — This will cause Psalm to ignore the code issue entirely.

When Psalm detects an issue will treat it based on error/code issue levels.

Example:

function foo() {
    return "foo";
}

As you can see, this function returns a string value, but the return type is missing. Psalm will consider it as a code issue called MissingReturnType.

That code issue belongs to error levels 1 and 2, which means:

  • In error level 3 or above, the issue will be ignored.
  • In error levels 1 or 2, the issue will be treaty as an error.
  • In error levels 1 or 2 with suppress configuration like ‘@psalm-suppress MissingReturnType’ above the function. Psalm will ignore the code issue on that function only.

Notes:

There are two places where you can suppress code issues:

  • In Psalm configuration.
  • In the Docblock function, e.g. :
<?php
/**
 * @psalm-suppress InvalidReturnType
 */
function (int $a) : string {
  return $a;
}

How to use Psalm:

The latest stable Psalm version requires at least PHP v7.4 and Composer

composer require --dev vimeo/psalm

Psalm is smart enough to initialize the configuration and add the appropriate error level predicated on your codebase:

vendor/bin/psalm --init

A new XML file configuration will be added and might look like this:

<?xml version="1.0"?>
<psalm errorLevel="6">
    <projectFiles>
        <directory name="src" />
        <ignoreFiles>
            <directory name="vendor" />
        </ignoreFiles>
    </projectFiles>
</psalm>

The configuration is quite simple. It defines error levels, scans directories, and ignores directories. You can find other possible configuration options on the official website.

To start scanning, run the following command:

vendor/bin/psalm

Psalm can automatically fix some issues based on codes issues, e.g.:

vendor/bin/psalm --alter --issues=InvalidReturnType

Bonus:

For better use of Psalm, especially in a big project:

  • Commit your code before running Psalm to avoid mixing your functional changes with Psalm changes, which might lead to a difficult recovery.
  • Initially, run Psalm with a high error level, and if you get many errors, try to:
    • ▹ Update the configuration to exclude code issues you do not need.
    • ▹ Use a lenient error level (5–6–7) at the beginning.
    • ▹ Split scanning by directories.
  • Test code after each update to make sure everything works.
  • Run Psalm before pushing your commits or inject it using Git hook.
  • Add Psalm to your CI pipeline.

Done.

Hope you enjoyed reading it. Feel free to criticize.

Cheers!!

This post is originated from my account on Medium