Start using PHPStan today

Victor Todoran
5 min readMay 11, 2022

--

PHPStan has a very comprehensive yet concise documentation which won’t take you more than a day to read and try out. The point of this article is not to double that documentation. The goal of this article is to encourage you to add PHPStan to your codebase today.

When looking at a piece of code there are some things that can be determined as wrong without even running it. This includes, but is not limited to:

  • Calling a non existing method
  • Calling a method with the wrong parameter type or count
  • Calling a method on null
  • Returning the wrong type or forgetting to return the result of a method

Ideally you might also want to enforce some common sense coding standards inside your codebase. Examples of such guidelines include:

  • No unused methods or variables lying around. This includes variables that are only set but never used.
  • Strict types everywhere
  • No generic array return types. In most cases, as part of the contract of a method, I want to ensure that an array has only strings, only integers or only instances of the TotalCalculator interface.

PHPStan can help you with all that and more, as we are going to see soon.

How to install

Adding PHPstan to your project is as easy as running

composer require --dev phpstan/phpstan

This will usually (depending on your composer configuration) add an executable vendor/bin/phpstan. You can already start analyzing, just run:

vendor/bin/phpstan analyse src/Path/To/Some/File.php

There is also an option to use PHPStan via docker, without adding it as a dependency to your project. This comes in handy if you don’t have enough rights to add new dependencies to the project. The approach is documented here, that being said, for simplicity and personal preference reasons I’m going to leave docker out of the rest of this post. If you decide to go with the docker approach this and this is something you should take into account.

Levels

The most common push back when proposing the integration of a static analysis tool is the fact that the code is already a mess and existing problems would bring development to a halt.

PHPStan is mindful about that and offers several levels of various strictness. This allows incremental adoption of PHPStan in already existing projects. Currently there are ten levels (0–9). Strictness grows with the level.

  1. basic checks, unknown classes, unknown functions, unknown methods called on $this, wrong number of arguments passed to those methods and functions, always undefined variables
  2. possibly undefined variables, unknown magic methods and properties on classes with __call and __get
  3. unknown methods checked on all expressions (not just $this), validating PHPDocs
  4. return types, types assigned to properties
  5. basic dead code checking — always false instanceof and other type checks, dead else branches, unreachable code after return; etc.
  6. checking types of arguments passed to methods and functions
  7. report missing typehints
  8. report partially wrong union types — if you call a method that only exists on some types in a union type, level 7 starts to report that; other possibly incorrect situations
  9. report calling methods and accessing properties on nullable types
  10. be strict about the mixed type - the only allowed operation you can do with it is to pass it to another mixed

As you can see levels also give you an idea on what PHPStan can do for you.

Personally I find 6 to be a balanced choice when it comes to strictness with the maximum level being the ultimate goal. To configure the level you can pass the -l option as follows:

vendor/bin/phpstan analyse -l 6 src/Path/To/Some/Dir

Configuration

PHPStan uses configuration format called NEON which is pretty similar to yaml. You can pass which configuration file to use via the -c command line option as such:

vendor/bin/phpstan analyse -c phpstan.neon

Inside the configuration file you can specify which level to be used, which paths to be analysed, which errors to be ignored and much more, for the full list see here.

It’s important to note that you can use more than one configuration file per project|pipeline. Say you are doing an ongoing migration from some code written ten years ago to a shiny new Symfony app. You prob have the legacy app in one folder and the Symfony app in another and you want to use different levels for each.

It’s useful to know that if you do not provide a config file explicitly, PHPStan will look for files named phpstan.neon or phpstan.neon.dist in current directory. For the rest of the article I will not pass the config file when analyzing and will let PHPStan resolve it on it’s own.

Baseline aka Ignoring Errors

In the Levels topic I was mentioning that people are reticent to adopt static analysis because of the current state of the project. It might be that we don’t want to deal with all existing problems right now but we want to start using static analysis immediately and also make it a pipeline breaking condition.

PHPStan has your back. You can ignore all existing errors automatically.
For this your phpstan.neon.dist might look something like this:

# phpstan.neon.dist
includes:
- phpstan-baseline.neon
parameters:
level: 6

It’s important that phpstan-baseline.neon exists and it is, initially, just an empty file at the same level as phpstan.neon.dist.

Then you run the analysis with the generate-baseline option:

vendor/bin/phpstan analyse src/Service --generate-baseline

After running the analysis, assuming your files had some errors the phpstan-baseline.neon file will look something like this

Running the command again, without the generate-baseline option will ignore these errors.

Hopefully I’ve sparked your interest enough and you can’t wait to add PHPStan to your project. For more info be sure to check the docs.

You should also know that there is a PHPStan Pro version. Paying for that helps the development of PHPStan. I’m not affiliated in any way, I just think they do an awesome job.

That’s it! Thanks for reading!

Disclaimer: Consider this to be a living document, which means it’s subject to undocumented changes and it might even die in the future.

--

--

Victor Todoran

I write, read and think about software and its users for a living