Quentin Delcourt

Learning from open source PHP projects - Part 2 - Static analysis

Just as TypeScript has become the best way to ship solid JavaScript code, PHP type system is now inseparable from its static analysis tools: Psalm and PHPStan. A PHPStan user myself, I had a bit of uncertainty in regards to where Psalm and PHPStan stand. Is one better than the other? Do they accomplish the same things? What is a static analyzer anyway? So let's try and see more clearly.
Static analysis is about telling if a software contains a bug without actually running it. These systems parse the code and try to find anything that could lead to a crash or a lack of precision.

Let's check our 5 open source projects again and look at what they use:

So, in our very little group, we can see that PHPStan is almost everywhere. But we also see that Psalm is far from being out of the radar yet.

PHPStan

Let's compare the PHPStan configurations first. The strictness level can go from 0 (very limited checks) to 9 for PHPStan v1, and up to 10 for PHPStan v2 (highest amounts of checks). If you play videogames, it's a bit like choosing your difficulty level. But the more difficult it is, the more confident you will be in your code. At the time of writing, here are the levels for each projects:

My initial thought was that probably the oldest projects in the list would use lowest levels of checks, but that is not necessarily the case. EventSauce for example was started in 2017 and has the highest level. While Tempest is a relatively new project and uses level 5. So this might indicate also that there might be some preferences from the developing team to keep some flexibility in the pace of development.

Well, let's see what we can learn by looking at those configuration files.

Tempest's configuration has an interesting feature I didn't know about, that comes from a package: disallowedFunctionCalls. Within Tempest, they use it to prohibit usage of methods such as exec(), eval(), phpinfo(). Quite useful especially when you receive code from people who might be doing mischievous things with your project. On top of this dd(), dump() and var_dump() are also prohibited. Quite the time-saver, has I cannot recall the amount of time I had to ask remains of variable dumps to be removed from a pull request. Better let PHPStan prohibit that for us. Definitely something I'll reuse in other projects.

Another interesting feature used by Tempest is the phpat package. It provides an easy to use API to define authorized relationship between classes in the project. Readers being familiar with architecture definitions of a project know all too well that as soon as they turn their eyes, other developers will happily break the rules, leaving the project in architecture limbo in no time.

BetterReflection is using a package for PHPStan and PHPUnit called phpstan-phpunit. It allows PHPStan to interpret mock objects created by PHPUnit as an intersection of the object that is mocked and the PHPUnit_Framework_MockObject_MockObject class.

All projects have exclusion filters, so there are always a few cases where you want these warnings to be silenced. Most notably the test classes seems to be muted a lot.

Psalm

Psalm also has error levels, and it's in reverse order compared to PHPStan: level 1 is the strictest, while level 8 is the least strict. Both BetterReflection and psl use level 1.

Just like PHPStan, Psalm allows the use of a baseline, so it can easily be integrated into an existing project.

The configuration files of both projects do not learn us much besides little tweaks linked to the particularities of the codebase.