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.