Back to Course |
Larastan: Catch Bugs with Static Analysis

Don't Get Scared by Errors

Let's look at a scenario where you have an older project that's already running pretty well and you just installed Larastan and ran the ./vendor/bin/phpstan analyse command for the first time:

[ERROR] Found 1289 errors

That's a lot of errors!

The first thought that comes to your mind after scrolling the list is - "It will take AGES to fix all of them! Not worth it, I don't have time for this!". But fear not, Larastan comes with a nice feature called Baseline generation which will help you with this. Let's see how it works.

Baseline Generation

To generate a baseline, you need to run the ./vendor/bin/phpstan analyse command with the --generate-baseline option:

vendor/bin/phpstan analyse --generate-baseline

This will generate a phpstan-baseline.neon file in the root of your project. This file contains all the errors that were found during the analysis. It also contains a list of all the files that were ignored during the analysis. This prevents the same errors from being displayed and will help you to focus on the new errors.

In our case, the command outputs the following with a level 3 run:

[OK] Baseline generated with 12 errors.

We'll see that a new file called phpstan-baseline.neon was generated in our root directory with the following content:

parameters:
ignoreErrors:
-
message: "#^Relation 'status' is not found in App\\\\Models\\\\Client model\\.$#"
count: 1
path: app/Http/Controllers/Admin/ClientController.php
 
-
message: "#^Relation 'project' is not found in App\\\\Models\\\\Document model\\.$#"
count: 1
path: app/Http/Controllers/Admin/DocumentController.php
 
-
message: "#^Relation 'project' is not found in App\\\\Models\\\\Note model\\.$#"
count: 1
path: app/Http/Controllers/Admin/NoteController.php
 
-
message: "#^Relation 'client' is not found in App\\\\Models\\\\Project model\\.$#"
count: 1
path: app/Http/Controllers/Admin/ProjectController.php
 
-
message: "#^Relation 'status' is not found in App\\\\Models\\\\Project model\\.$#"
count: 1
path: app/Http/Controllers/Admin/ProjectController.php
 
-
message: "#^Relation 'permissions' is not found in App\\\\Models\\\\Role model\\.$#"
count: 1
path: app/Http/Controllers/Admin/RolesController.php
 
-
message: "#^Relation 'roles' is not found in App\\\\Models\\\\User model\\.$#"
count: 1
path: app/Http/Controllers/Admin/UsersController.php
 
-
message: "#^Method App\\\\Http\\\\Controllers\\\\Auth\\\\RegisterController\\:\\:create\\(\\) has invalid return type App\\\\User\\.$#"
count: 1
path: app/Http/Controllers/Auth/RegisterController.php
 
-
message: "#^Method App\\\\Http\\\\Controllers\\\\Auth\\\\RegisterController\\:\\:create\\(\\) should return App\\\\User but returns App\\\\Models\\\\User\\.$#"
count: 1
path: app/Http/Controllers/Auth/RegisterController.php
 
-
message: "#^Access to an undefined property App\\\\Models\\\\Role\\:\\:\\$permissions\\.$#"
count: 1
path: app/Http/Middleware/AuthGates.php
 
-
message: "#^Relation 'permissions' is not found in App\\\\Models\\\\Role model\\.$#"
count: 1
path: app/Http/Middleware/AuthGates.php
 
-
message: "#^Cannot access property \\$id on object\\|string\\.$#"
count: 1
path: app/Http/Requests/UpdateUserRequest.php

To accept these ignored errors in our reports - we'll have to modify our phpstan.neon file:

includes:
- ./vendor/nunomaduro/larastan/extension.neon
# Add the following line:
- ./phpstan-baseline.neon
 
parameters:
paths:
- app/
# Level 9 is the highest level
level: 3

Now running the same command ./vendor/bin/phpstan analyze with level 3 will ignore those errors:

[OK] No errors

But if we change to level 7 (randomly selected high level to track more things) and run it again - we'll get all the new errors in place:

[ERROR] Found 259 errors

And the errors list does not include any of the baseline issues, which is great as only new things are shown.

Example with Baseline Generated

Let's make sure that our new code is covered with the Larastan checks after our baseline is set:

app/Http/Controllers/Admin/UsersController.php

public function index() {
// ...
 
$users = User::with(['roles', 'permissions'])->get();
 
// ...
}

Running ./vendor/bin/phpstan analyze will now show us:

Line Http/Controllers/Admin/UsersController.php
------ ---------------------------------------------------------------
21 Relation 'permissions' is not found in App\Models\User model.
------ ---------------------------------------------------------------

We don't see anything about our roles relationship because it's in the baseline file:

phpstan-baseline.neon

-
message: "#^Relation 'roles' is not found in App\\\\Models\\\\User model\\.$#"
count: 1
path: app/Http/Controllers/Admin/UsersController.php

But we still see a new error being reported about our permissions relationship as it's not defined yet in our User model properly (can be a missing relationship or just a missing return type).

Conclusion

This is helpful to get you going with the important fixes rather than all the basic things. It will help you to get your future code to be safer than it was, while you don't have to constantly see all the previous error messages.

Of course, keep in mind that even PHPStan recommends you use this carefully:

It works best when you want to get rid of a few dozen to a few hundred reported errors that you don’t have time or energy to deal with right now. It’s not the best tool when you have 15,000 errors — you should probably spend more time configuring PHPStan or running it with a lower rule level.