PhpStan: improve your code quality

Manual code review is a hard task and everyone who tired that, probably will agree – it is because this method requires time, involves even several people and do not provide success, because anyone can just complain and do not agree. Fortuantely we can use additional tools like static code analyzers: they can check our codebase and inform us about any issues to avoid bugs before we will push something to production. In this post I would like to briefly describe PhpStan – one of great PHP static analyzers. It open source, completely free tool we can use to improve our codebase quality.

Table of Contents

Usage

Using PhpStan is very simple. First of all, we need to install it:

composer require --dev phpstan/phpstan

After, we can analyze our codebase, for example in Laravel projects, by scanning app directory:

vendor/bin/phpstan analyse app

It will display information about all detected issues, for example wrong variable types passed into methods, unkown classes, unused parts of code and much more. It has more advantages, because will force developers to write some comments in codebase: these comments are used also to analyze, to make “everything clear” and can help other people to understand code. Many benefits and in reality, no real downsides, so if we can, we definately should use PhpStan.

Package has many configuration options, and we can provide them on command line, or – and it is much better method – as config file, in default it’s phpstan.neon. I do not want to spend there a lot of time to describing all options, because it does not make any sense – everything is available in official documentation. Instead, I would like to mention only few items.

First of all, level option. It determines how strict will be our PhpStan configuration from 0 to 9 (where 9 is the hardest configuration). Default config is 0, but I really recommend to use level 6 or higher: they just provide tons of good practices and if we decided to use static analysis tool, we need to bring better quality to our codebase, right?

Second option is caching – PhpStan can be slow… or maybe not slow, because it is amazing and optimized tool, but with bigger projects full analyze can take a lot of time. You can have an idea of scanning only modified files… Nope, it is not a right way – it is because even if analyzer will not find anything in your modified files, it does not mean you did not break anything else in other places. Only full scanning can you give clear answers. Instead of such methods, caching should be used. To do this, you need to provide cache path in configuration file, for example something inside tmp directory:

parameters:
    paths:
        - app

    level: 6

    tmpDir: /tmp/phpstan

Caching will speed up PhpStan a lot – first scan can be slow, but next scans will be much faster. There are many situations when cache will be automaticaly invalidated, but they needs some important changes like composer.json changes or PhpStan config changes. They are not often, so we can use cache daily without isues.

Very good practice is to use PhpStan baseline. If you start completely new project, it should not be a problem to fix some detected issues, but with bigger ones with a lot of legacy… It will be very, very difficult. To avoid that, you can create baseline file and just “start from scratch” – all entries detected by PhpStan will be saved as exclusions and you can focus on new codebase. Geneting baseline is very simple, you only need to use proper parameter:

./vendor/bin/phpstan analyse --configuration phpstan.neon --generate-baseline

After that, PhpStan will inform you about new baseline, for example:

 [OK] Baseline generated with 102 errors.

After, you should add newly generated baseline file to includes section in phpstan config file:

includes:
    - ./phpstan-baseline.neon

And it’s all, after next analyze, PhpStan will inform about zero errors, so instead of fixing legacy, you can focus on new parts and take care about code quality.

Some libraries provide their PhpStan baselines, there are also ready to use packages for specific tools. For example larastan – baseline prepared for Laravel.

PhpStan on CI

Of course, we can limit Phpstan usage to only our machine or just local usage if our team is ridiculously small. In such scenario, maybe we even do not use any continuous integration tools. With bigger scale and bigger projects, you probably use them, so should consider put PhpStan into CI as a job to check all merged code. Why? It provides automatic testing and can be used even before manual code review – just to avoid time wasting for many possible errors or bad practices. It is fully automatic, so developers cannot ignore messages. If PhpStan will detect any issues and trigger an error, MR will be blocked until preparing fixes.

Below, I present example script for Gitlab CI which can be used to provide automatic PhpStan analyze for all merge requests. Of course, it is only an example: I’ve decided to increase memory limit to 2 GB and also use cache for directory mentioned in config above. Your configuration can be completely different, so please adjust. If you also want to use cache, remember to save it only if PhpStan job will end with success – if you will cache results with errors, other merge requests can also display them, even if developers did not touch the same codebase

phpstan:
  cache:
    - key: phpstan
      paths:
        - /tmp/phpstan
      policy: pull-push
      when: on_success
  script:
    - php -d memory_limit=2G vendor/bin/phpstan analyse -c phpstan.neon