DEV Community

Cover image for How to improve your code quality with Psalm — a static analysis tool
Maroje Macola for Bornfight

Posted on • Updated on • Originally published at bornfight.com

How to improve your code quality with Psalm — a static analysis tool

Intro

Before going into the main topic, let’s clarify some things. “Psalm” might be hinting at something religious, but it’s just a tool name, which is short for PHP Static Analysis Linting Machine. It is meant for PHP developers — and it was made by the crew from Vimeo, who have realised some 5 years ago that they could really use a tool which will help them find unspotted bugs and/or errors before releasing their code to production.

Code quality tools

Any tool which improves our code can be classified as a code quality tool. At Bornfight, we use several of them when developing with PHP:

  • PHPCSFixer — coding standards fixer, for enforcing single coding standard throughout the project
  • PHPCPD — copy/paste detector, for detecting duplicate code
  • PHPMD — mess detector, for enforcing rules in areas like clean code, code size, naming etc.
  • PHPStan — static analysis tool, similar to Psalm

After reading the last bullet from the list, you may be asking yourself why is this post talking about Psalm, a static analysis tool that we don’t use (since it’s not on the list), and not about a similar tool, PHPStan, which we actually use. Well, my dear reader, I find that the best way to force yourself to research a topic is by writing a post or holding an education for someone. More so, if the tool proves itself useful, it can be a great addition to the existing CI pipeline or maybe even a replacement for PHPStan. Anyway, let’s go deeper into it.

Static… what?!

So, “Static Analysis Linting Machine”? Those are some quite powerful words. Static analysis obviously means that it analyses something, in this case our code, but without executing it. Word “lint” has multiple definitions online, and one of the non-software-related ones I found is “clinging fuzzy fluff that accumulates in one's pockets or navel”. Okay, it doesn’t feel like it’s helping in explanation, but I will try to use it anyway. While writing code, we (should) try our best not to make bugs. Still, no matter how hard we try, over time, before releasing it to the production, codebase (pocket) accumulates unspotted bugs (clinging fuzzy fluff). And we should strive to have both our codebase and pockets clean.

That's where Psalm steps in and helps us in achieving so (at least for codebase, we still have to clean pockets ourselves).

Give me some features

After cleaning up some questions around Psalm and static analysis tools, we are still asking ourselves, what kind of bugs or possible errors does it discover? Well, even though development with PHP can be enjoyable, it is important to be aware of its pros and cons. Since it’s an interpreted language, rather than compiled, it does not enforce type safety.

Here’s a simple example of working code:

function doubleTheNumber($number) {
  return $number * 2;
}

$number = 5;
echo doubleTheNumber($number);
Enter fullscreen mode Exit fullscreen mode

But, it can also be written with type hints:

function doubleTheNumber(int $number): int {
  return $number * 2;
}

$number = 5;
echo doubleTheNumber($number);
Enter fullscreen mode Exit fullscreen mode

The second way is much safer because, with type hints, we don’t allow passing non-integer values to the function, but also if we need to use the function's return value, we are sure that it will be an integer.

If we passed an empty array, running Psalm would tell us something like:

ERROR: InvalidArgument - 8:22 - Argument 1 of doubleTheNumber expects int,
array<empty, empty> provided - https://psalm.dev/004
Enter fullscreen mode Exit fullscreen mode

Cool, right? Type-checking is its most important feature. Issues also contain links to the dedicated page (psalm.dev/004 in this case), with its explanation and help in fixing. By investigating and resolving an error, we are actually learning how to write better code and what are some of the bad practices in PHP and programming in general.

If you think about adding Psalm to an existing codebase, but feel like it will throw too many type-related errors, there is also a solution. One of the features is called Psalter (nope, we are still not talking about anything religious). It can fix a number of issues it finds, like adding missing type-hints, or even removing dead code, like unused variables or functions.

Another scenario could be that the codebase is massive and there is no time to fix all of the issues. But that does not mean that you should continue writing buggy code. And that’s where the Baseline feature steps in — it allows you to grandfather-in all the errors found. It stores all the errors in a file and does not mention them ever again, but it will show every new error which is produced with new code written after activating Baseline.

Alt Text

Since Psalm checks for many types of errors, depending on the developers knowledge and other factors, it can be overwhelming to deal with all of them. That’s where level strictness comes in handy. There are 8 levels of strictness, where number 1 is the most strict. The stricter the level, the more error types are included, and vice versa.

Sometimes, there is a need to exclude a whole directory from being analysed, or just a specific type error on a specific method. This can be done by suppressing the errors either within the configuration file or via a docblock.

Here’s an example for the latter:

class Foo {
    private string $bar = 'bar';

    public function getBar() : string {
        return $this->bar;
    }
}

$a = new Foo();
/** @psalm-suppress UnusedMethodCall */
$a->getBar();
Enter fullscreen mode Exit fullscreen mode

Any level of strictness would usually throw something like:

ERROR: UnusedMethodCall - 12:5 - The call to Foo::getBar is not used
Enter fullscreen mode Exit fullscreen mode

but it will not be mentioned as long as it’s suppressed.

Since Psalm supports a large number of docblock annotations, it’s important to use them in order to utilize the most out of Psalm’s type-checking feature. It even has its own annotations, called template and assert annotations. Through research so far, I feel like they are a vital part of this tool, and maybe they will deserve their own blog post, after I manage to test them out more.

Conclusion

Having non-typed code might be working at the moment, but working as a developer means to always think ahead. Writing any new code in such a codebase can be more stressful and scary, especially for a new developer on a project. As codebase gets larger and larger, and unpredicted bugs pop-up more often, introducing a static analysis tool, such as Psalm, can be very helpful in tackling those problems.

Also, through dealing with Psalms issues and warnings in the codebase, developers are learning how to write better and maintainable code, which is something that every developer should strive for. Don’t forget, less bugs means happier clients, and there’s no need to say how important that is in business!

If this post was useful to you and you’d like to know more about Psalm, let me know. After having some more practice with Psalm, I think I could write about more in-depth usage of it, or compare it with PHPStan and see where it goes.

What about you?

What are your thoughts on the subject? If you have experience with Psalm in particular, or with any other static analysis tool, I would be glad to hear your opinion about it, so feel free to leave a comment below :)

Top comments (0)