Level up your Laravel code with PHPStan

Sandip ShresthaSandip Shrestha
4 min read

PHPStan is a static analysis tool that helps developers identify potential bugs and issues in their code before they occur. It scans your whole codebase and looks for both obvious & tricky bugs. Even in those rarely executed if statements that certainly aren't covered by tests.

In this article, we will discuss how to set up and use PHPStan in Laravel using Larastan.

⚙️ Setting up PHPStan in Laravel using Larastan

Step 1: Install Larastan

First, we'll need to install Larastan as a development dependency in your Laravel project. You can do this by running the following command:

composer require --dev nunomaduro/larastan

Step 2: Configure PHPStan

Once we've installed PHPStan and Larastan, we'll need to create a PHPStan configuration file in your Laravel project's root directory. We can do this by creating a file named phpstan.neon and adding the following contents:

 includes:
    - ./vendor/nunomaduro/larastan/extension.neon

parameters:
    paths:
        - app
        - database
        - routes
        - tests

    level: 6

The parameter paths in the config file tell us which folders to analyse and the parameter level tells us the level of phpStan rule to enforce.

Step 3: Run PHPStan

Once we have configured PHPStan, you can run it by using the following command:

./vendor/bin/phpstan analyse


📈 PHPStan Rule Levels

We can currently choose from 10 levels (0 is the loosest and 9 is the strictest) by passing -l|--level to the analyse command or specifying it in the phpstan.neon file. This feature enables incremental adoption of PHPStan checks.

These are the different levels of PHPStan rules and a short description of what they check.

Level 0:

It analyses for basic checks, unknown classes, unknown functions, unknown methods called on $this, the wrong number of arguments passed to those methods and functions, always undefined variables etc.

The above output shows errors on undefined variables, undefined constants, the wrong number of parameters passed and so on.

Level 1:

It analyses for possibly undefined variables, unknown magic methods and properties on classes with __call and __get etc.

The above output shows errors on unused variable use in function, unnecessary expression calculation and so on.

Level 2:

It analyses for unknown methods checked on all expressions (not just $this), validating PHPDocs etc.

The above output shows errors on undefined methods such as count() and so on.

Level 3:

It analyses return types, types assigned to properties etc.

The above output shows errors on return types, types assigned to properties and so on.

Level 4:

It analyses for basic dead code - always false instanceof and other type checks, dead else branches, unreachable code after return; etc.

The above output shows errors on basic dead code, unreachable code and so on.

Level 5:

It checks for types of arguments passed to methods and functions.

The above output shows errors on types of arguments passed to ClientListExportedNotification in routes.dev.

Level 6:

It reports missing type hints.

Level 7:

It reports 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

Level 8:

It reports calling methods and accessing properties on nullable types

Level 9:

It will be strict about the mixed type - the only allowed operation you can do with it is to pass it to another mixed


💭 Closing thoughts

If we’ve got a legacy project and we fire the PHPStan task runner at level 9, we might be overwhelmed by the results it produces. Everything is broken! To refactor, I’d suggest the following:

Set our milestones for each level identified, and start small. Then set the top level we are willing to go to when classifying “fixed the tech debt” under our own “definition of done” A good de-facto target for a legacy project is to get Rule Level 6 passing. It’s at this point where our codebase can likely transition from a state of “danger” to “correct”.

We can pump up the PHPStan checking level later and make our codebase as bug-free as possible.

You can find more information about Larastan and PHPStan in its GitHub repository. It's worth running it on your codebase, and you'll probably find bugs you looked over.

12
Subscribe to my newsletter

Read articles from Sandip Shrestha directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sandip Shrestha
Sandip Shrestha

I am a Full stack Software Engineer and also a hobbyist writer who writes about Software Development and its allied intricacies. I hold on to my methods loosely, embrace flexibility & modularity and believe we can always grow.