Courses

Larastan: Catch Bugs with Static Analysis

Intro, Installation and Common Errors

So, what does Larastan actually do? It shows you potential errors in your code with just one terminal command! Or even better - right in your editor. Let's look at what it brings

We've run ./vendor/bin/phpstan analyze and got the following output:

Look how many issues it spotted! And it's not just random issues - these issues can cause bugs in your code. Scary, right?

So, now, let's start with Larastan and learn how to fix those issues.


Installation and Setup

First, install the package via composer:

composer require --dev nunomaduro/larastan

Then create a phpstan.neon file in the root of your project:

phpstan.neon

includes:
- ./vendor/nunomaduro/larastan/extension.neon
 
parameters:
paths:
- app/
 
# Level 9 is the highest level
level: 5

Don't mind the levels yet - we'll look into those soon!

Next on our list is to run the analysis. To do that, run the following command:

./vendor/bin/phpstan analyse

You should see something like this:

And that's it, that's how default Larastan works! But, of course, there's much more under the hood.

On the first run, you might see a huge list (which depends on the project size) of errors. Don't worry - you don't have to jump and fix them yet! Let's first take you through the basics of what you can expect to see and how to resolve the issues!

Let's start simple and grow from there.


First Common Errors You'll See

Before we dive deeper into the most common issues you'll see - let's make sure that we can read the errors properly. These errors are grouped by the file they are in with lines where you'll find the error exactly. For example:

------ ---------------------------------------------------------------
Line app/Http/Controllers/ExampleController.php
------ ---------------------------------------------------------------
12 Undefined variable: $example
------ ---------------------------------------------------------------

This error is in the app/Http/Controllers/ExampleController.php file on line 12. The error itself is Undefined variable: $example. Quite simple, right? Not that scary once we know what to look for.

Now let's look at the most common ones you could encounter:

Undefined Variable

------ ---------------------------------------------------------------
Line app/Http/Controllers/ExampleController.php
------ ---------------------------------------------------------------
12 Variable $example might not be defined.
------ ---------------------------------------------------------------

It might seem scary, but it actually found a variable in your code that you didn't define and yet it was used. This is a great example of how Larastan can help you find bugs in your code. To fix this, you can either define the variable or remove its usage of it.

Undefined Method

------ ---------------------------------------------------------------
Line app/Http/Controllers/ExampleController.php
------ ---------------------------------------------------------------
12 Call to an undefined method Illuminate\Http\Request::example().
------ ---------------------------------------------------------------

This is a similar error to the one above. It found a method that you called, but it doesn't exist. In this case, you can either define the method or remove the call.

Too Many Parameters Passed to A Method

------ ---------------------------------------------------------------
Line app/Http/Controllers/ExampleController.php
------ ---------------------------------------------------------------
12 Too many arguments for method Illuminate\Http\Request::example().
------ ---------------------------------------------------------------

This error indicates that somewhere in your code you passed too many arguments to a method. Remove them or add them to the method definition.

Many More Other Errors

There are a lot more issues you might see but the pattern will remain the same. You'll see a file, a line, and an error message. The error message will tell you what's wrong and how to fix it.

avatar

Precious addition as always. I just have started reading the course and I immediatly have a question. The things larastan is doing, most of the things already included in my phpStorm. At least it seems like that. Do you think, laraStan has something to offer even if I use phpStorm?

👍 2
avatar

PHPStorm is great at understanding your code and definitely gives you a lot of the same errors right in your editor. Where it lacks tho - understanding the strictly typed things. Few examples:

Example 1: Understanding when you are passing mixed data to a strictly typed function. This will not always show up in PHPSTorm by default.

Example 2: Displaying that a return type can be declared. In some cases PHPStorm alone doesn't display that you didn't define a return type. Installing PHPStan - instantly gives a warning. Great example is returning a view from the controller - PHPStorm usually doesn't trigger the error but PHPStan instantly does.

Example 3: Relationship definitions can be tricky. PHPStorm doesn't understand that you just tried to load with('roles') on user model, while PHPStan understands it and will trigger an error if there's no relationship or the relationship doesn't have a return type.

There's probably more ways that PHPStan extends what PHPStorm does due to the fact that PHPStan understands the code at a deeper level with Static analysis and PHPStorm has it's limitations at this moment. Both are good and PHPStan will just extend the understanding to give you more confidence :)

avatar

I setup the larastan plugin in the Mini-Course] Laravel Breeze with User Role Areas project and I am getting 1 error dealing with the (int) that we setup in hear

return match ((int)$this->role_id)

$ ./vendor/bin/phpstan analyse Note: Using configuration file C:\xampp\htdocs\awi_projects\project-1\phpstan.neon. 42/42 [============================] 100%

Line Models\User.php

49 Match expression does not handle remaining values: int<min, 0>|int<4, max>

[ERROR] Found 1 error

have a suggestion as to how to fix this ?

avatar

Could you provide the full code snippet of that match()? Then I could comment.

avatar

public function getRedirectRouteName(): string {

    return match ((int)$this->role_id)
    {
        1 => 'client.dashboard',
        2 => 'staff.dashboard',
        3 => 'admin.dashboard',
    };
}
avatar

In match you have a default that's available for you. You need to set it just in case it's more than 3:

    default => 'client.dashboard', // Or any other route 

This way, you'll have cases for 1, 2, 3, and then you'll cover any other (like 4) with a default. That's the issue Larastan is asking you about