Leveraging PHP Static Analysis in Popular Frameworks like Laravel

PHP
By naman
Optimize Laravel web app development with PHP Static Analysis

Code analysis is the process of testing the program to check the proper functioning of the software. The process aims to uncover defects or error-prone parts in a source code and fix them promptly. While coding testing can be dynamic or static, this article discusses leveraging PHP Static Analysis in the Laravel framework.

Static code analysis is done before the software testing begins to guarantee that the code you pass on to testing is error-free (Static errors like syntax errors, etc.). It provides an automated feedback loop that allows programmers to detect bugs early, making it easier and cheaper to fix those problems.

Our blog will use the PHPStan tool to run code analysis on the Laravel framework. Before we start, let's understand some code analysis jargon to learn things better.

Code Analysis Jargon

Before you move to PHPStan or any code analysis tool, you must be familiar with common terms in the code analysis process. You can think of these terms as what these code analysis tools will look for in your software.

Measurements

It checks for the program vocabulary, length, volume, and difficulty estimating the number of bugs in a module. The measurement aims to assess the code's complexity- the simpler the code, the better its quality will be. Simpler codes are also easy to maintain.

Naming: 

Checks the names of the variables and methods. They shouldn't be too short or too long. It also checks if the names of the variables and methods follow a naming convention like camel-case or not.

Type Hinting: 

Some code analysis tools suggest a name consistent with the return type, like getFoo() method (that returns a boolean) is better named isFoo().

Lines of Code: 

It checks the line of codes in your class/ method against a maximum value. It also checks for the number of the method's parameters or the class's number of public methods and properties.

Commented Code: 

No commented-out block of code is allowed (most of the time); as long as you are using a version control system, you can first remove the unused code and recover the same on a need basis. 

Return Statements: 

It checks for how many return statements you have throughout your method. Having too many return statements makes the method complicated. 

Return Types: 

It is important to ensure that the return type matches what you expect. Choose fewer return types to avoid any confusion with the analyzers.

Code Structure

Better code structure leads to better coordination and smoother integration of code changes in a program. 

Dedicated Exceptions:

Use the dedicated exceptions instead of generic run-time exceptions. Generic run time exceptions can be cached by client code.

No Static Calls: 

Static calls should be avoided in the code. Rather, one should choose dependency injection instead. (Factory methods are the exception).

DRY:

It is for checking the code duplication in code.

Complexity

The program's complexity increases with many control structures in one method, which complicates the job of static code analysis tools. You should do the following:

Include early return statements.
Combine multiple conditions in an if statement (Merging nested if statements) and use helper functions to make the condition readable.

Security Issues

Protecting and securing software programs from malicious threats further ensures the smooth working of the program/ software.

Cipher Algorithms: Choosing cryptographic systems resistant to cryptanalysis, like brute force attacks, will work great.

Cookies: Creating sensitive cookies with the "secure" flag not sent over an unencrypted HTTP request ensures security.

Dynamic Execution: While some APIs (Application program interface) allow the execution of dynamic code (as strings at runtime), most of the time, dynamic execution is frowned upon because of code injection risk.

Running PHPStan analysis tool

PHPStan focuses on code analysis before actually running it; that is, it works to catch bugs before you write tests for the code. One can say it moves PHP closer to other compiled languages, where each line of the code is checked before the programmer runs the actual line.

PHPStan has 0 to 10 levels; depending on the rules, you can select the level for your program. 

ProTip:

0 is the loosest, and 9 is the strictest; you can start with the lower level and increase it when you feel like it.

Using the baseline feature, you can also run a higher level without fixing all the reported errors first.

You can use --level max as an alias for the highest level; it allows you to stick to the highest level even after upgrading the tool.

Here is a brief:

Level 0

The tool does basic checks. It checks for unknown classes, functions, and methods called on $this. It also considers the wrong number of arguments passed to those methods and functions and always undefined variables.

Level 1

At this level, the tool checks for possibly undefined variables, unknown magic methods, and properties on classes with __call and __get.

Level 2

In this level, unknown methods are checked on all expressions, not just $this). It validates PHPDocs

Level 3

The tool checks return types and types assigned to properties.

Level 4

Here the PHPStan code analysis tool does basic dead code checking - always false instanceof and other type checks. It also checks for dead else branches and unreachable code after return, etc.

Level 5

It ensures checking of the types of arguments passed to methods and functions.

Level 6

The static code analysis tool, PHPStan reports missing typehints.

Level 7

Here, it reports partially wrong union types, that is, if you call a method that only exists on some types in a union type or other possibly incorrect situations.

Level 8

It reports calling methods and accessing properties on nullable types.

Level 9

Here, you can be strict about the mixed type. At this level, the only allowed operation you can do with it is to pass it to another mixed.

Setup PHPStan for Code Analysis

To get started with PHPStan on Laravel, you need a Larastan extension. The extension is useful when there are subjective bugs, or you want to accommodate a specific framework like Laravel while taking advantage of PHPStan capabilities.

Here are the steps that you should follow to Use PHPStan on Laravel:

1. Installation of PHPStan for Laravel

The step includes two processes:

Installing the Package with Composer

You can use the following code for installation:

composer require nunomaduro/larastan:^2.0 --dev

Here, we use PHP 8.0+ and Laravel 9.0+ for the installation process.

Start analyzing your code with the console command.

You can do it using the default configuration of PHPStan. Here is the code to write:

./vendor/bin/phpstan analyse app --memory-limit=25

Here, we set the path we want to analyze (app) and the memory limit (25 MB). For more commands, you can check PHPStan Command Line Usage.

2. Set the Configuration File

PHPStan uses either of the two configuration files, phpstan.neon or phpstan.neon.dist. Using these configurations, you can do the following:

  • Define the paths that you want to analyze
  • Set the rule level
  • Exclude paths
  • Include PHPStan extensions
  • Set the maximum number of parallel processes
     

Let’s learn it better by setting a simple configuration file that is in the root directory of your application software by default. Check out the code:

includes:
   - ./vendor/nunomaduro/larastan/extension.neon
parameters:
   paths:
       - app
       - config
       - database
       - routes
   # The level 9 is the highest
   level: 5
   ignoreErrors:
       - '#PHPDoc tag @var#'
   parallel:
       maximumNumberOfProcesses: 4
   noUnnecessaryCollectionCall: false
   checkMissingIterableValueType: false

3. Ignore the Errors

You need to ignore certain errors while programming the software for desired outputs. Luckily with PHPStan, you can do it by following either of the two ways:

  • Inline

You do it using PHPDoc tags. Check out the code.

   function () {
      /** @phpstan-ignore-next-line */
      echo $foo;
      echo $bar /** @phpstan-ignore-line */
  }

  • From the configuration file

Here is the code:

parameters:
        ignoreErrors:
            -
                message: 'Access to an undefined property [a-zA-Z0-9\_]+::\$foo'
                path: some/dir/someFile.php
            -
                message: '#Call to an undefined method [a-zA-Z0-9\_]+::doFoo()#'
                path: other/dir/DifferentFile.php
                count: 2 # optional, to ignore the first two error occurrences
         -
                message: '#Call to an undefined method [a-zA-Z0-9\_]+::doBar()#'
                paths:
                    - some/dir/*
                    - other/dir/*

ProTip: We recommend using it via configuration file.

4. Set the Baseline

Introduce PHPStan to the CI (Continuous integration) pipeline. It would be better to increase the strictness level of PHPStan or even upgrade to a newer version.

With PHPStan, you can allow a certain list of errors as the “Baseline,” and it will stop reporting them in subsequent runs.
ProTip: To export the current list of errors and set it as the baseline, you should run PHPStan with the-generate-baseline option.

./vendor/bin/phpstan analyse --memory-limit=25 --generate-base

Here, We dropped the path option from the example in installation. It is set in the config file. As a result, it generates the list of errors and saves it in phpstan-baseline.neon.

You can now add the baseline file to includes using the following code:

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

5. Add PHPStan to the CI/CD pipeline
 

You can now integrate PHPStan to the CI/CD pipeline. To improve code quality, you should run it regularly on merge requests and main branches. It also helps in code review.

stages: 
 - staticanalysis - 
phpstan:
 stage: staticanalysis
 image: composer
 before_script:
   - composer require nunomaduro/larastan:1.0.2 --dev --no-plugins --no-interaction --no-scripts --prefer-dist --ignore-platform-reqs
 script:
   - vendor/bin/phpstan analyse --no-progress --error-format gitlab > phpstan.json
 cache:
   key: ${CI_COMMIT_REF_SLUG}-composer-larastan
   paths:
     - vendor/
 artifacts:
   when: always
   reports:
     codequality: phpstan.json
 allow_failure: true
 dependencies:
   - php-cs-fixer
 needs: 
   - php-cs-fixer
 only:
   - merge_requests
   - master
   - develop
   - /^release\/[0-9]+.[0-9]+.[0-9]$/
   - /^hotfix\/[0-9]+.[0-9]+.[0-9]$/

And we are all good. :)

Summary

Laravel is an open-source web framework intended for app development following the model–view–controller architectural pattern. We briefly explained how to set up the PHPStan code analyzer for your Laravel project. We hope you got a good overview of it.

share on :

Profile picture for user naman
naman
Naman Saxena, an SEO executive, excels in optimizing digital presence and driving online growth, helping businesses enhance visibility and achieve marketing goals.