PHPStan is a static analysis system for PHP projects. It finds bugs in your codebase by inspecting the source files. You don’t have to run your code or manually write tests to find problems!
The term “static analysis” is defined as debugging code without actually executing it. It is mostly used with interpreted languages, such as PHP, as the problems it encounters tend to surface at the compilation stage in compiled languages.
Static analysis works best when performed within a well-structured, highly-typed codebase. This is especially important in the case of PHPStan, as it is technically a hybrid analysis tool.
Contrary to our definition of static analysis, PHPStan will actually load and run your source files. This is because it partially takes advantage of PHP̵
Consequently, the updates will be performed at the base of the script:
function example() : void { echo "Example output"; } example();
Would PHPStan analyze the file shown above, you would notice Example output
broadcast to the console. For this reason, it is best to run PHPStan against inert source files (containing only classes and functions) that have no side effects when loaded.
Add PHPStan to your project
To use PHPStan, you need PHP 7.1 or newer. This requirement only applies to the version of PHP used to run PHPStan itself. The tool can analyze source files targeting older versions of PHP.
It is recommended to use Composer to add PHPStan as a dependency:
composer require --dev phpstan/phpstan
The binary PHPStan file will be added to your project at vendor/bin/phpstan
. You can now use it for the first time to analyze your codebase:
vendor/bin/phpstan analyse src
The above command will run PHPStan’s tests for all source files in your src
directory. Depending on the size of your codebase, this could take a few minutes.
You see a green “[OK] No mistakes ”if all tests pass. Otherwise, the list of errors found will be displayed. Follow the instructions displayed to resolve any error before restarting PHPStan.
Error types and levels
PHPStan includes a plethora of controls for a wide variety of potential codebase problems. Some of the most common you will come across include:
- Type system problems – Assigning an invalid value to a typed property, or passing incorrectly typed parameters to a method. This also includes contract issues such as a class improperly implementing an interface.
- Function calls – Passing too many or too few parameters when calling a function or method (eg 3 instead of 4).
- Unknown classes, methods and functions – Try to use something that doesn’t exist in the codebase.
- Access to undefined / possibly undefined variables – Trying to use a variable that is not defined within a certain range, or that does not always have a value, but is used in an assumed context.
- Check dead code – Marking of useless code, such as Boolean equations that always lead to the same value and code branches that are never executed (eg Code following
return
statement within functions).
Rules are divided into 9 different “levels” labeled from 0 to 8. The special level max
acts as an alias for the highest possible level. Over time, PHPStan can add additional numeric levels, so used max
ensures that you always get the strictest checks possible.
PHPStan outputs level 0 by default. This includes only the most basic tests. It’s a good idea to let your codebase pass each level individually before moving on to the next. Mature projects are likely to encounter a different set of problems with each new level.
To change the level that PHPStan uses, you can use the --level
command line parameter:
vendor/bin/phpstan analyse src --level 8
In addition to the built-in controls, PHPStan extensions are available to add even more functionality. You can also write your own rules. This is useful when you are deprecating functionality that developers should no longer use in new code. We’ll cover creating custom rules in a future article.
Configure PHPStan
In addition to the initial experiments, using PHPStan’s command line interface can quickly become tiresome. It’s best to add a configuration file to your project that can then be assigned to source control for all of your developers to use.
PHPStan uses the Neon configuration file format, which has a syntax very similar to YAML. make a phpstan.neon
file in the root folder of your project. This file will be loaded automatically when PHPStan starts, so you can now use the analyse
command without further arguments:
vendor/bin/phpstan analyse
To overwrite the configuration file in use, enter the --configuration
flag:
vendor/bin/phpstan analyse --configuration /phpstan-config.neon
You now need your phpstan.neon
file with some content. A good starting point could look like this:
parameters: level: 0 paths: - src
This basic configuration file should give the same output as the command line call shown earlier. You can add additional folders to scan as new lines in the paths
section. To exclude files and folders, add them to a excludes_analyse
sheet within the same parameters
section.
Ignore errors
Occasionally, PHPStan can reveal a problem that is unavoidable. If there is an issue that you cannot fix immediately, you may want to explicitly ignore it for the tests to pass.
This is especially important if you want to move to a different level of control, or if you are using PHPStan in a CI environment where a failed run will stop the deployment of your build. But don’t take this course of action lightly – you should only choose to ignore a reported error if you’re sure it’s safe to do so.
After making the decision, add a new one ignoreErrors
section within it parameters
of your configuration file. You must define the matching message as a regex and the paths to apply the exclusion to:
parameters: level: 0 paths: - src ignoreErrors: - message: '/Return type string of method ExampleClass::example() is not covariant(.*).' path: src/ExampleClass.php
You can specify optionally paths
as a series of paths, replacing the single ones path
key shown above.
Optional rules
The severity of PHPStan can be adjusted by a series of configuration variables. This allows you to fine-tune the checks performed outside the level system described above. Some of these are potentially controversial or probably don’t match all private style guides, so they are turned off by default.
A few settings that might be worth checking out include:
checkAlwaysTrueInstanceof
– Marks use ofinstanceof
which will always evaluate totrue
.checkAlwaysTrueStrictComparison
– Flags when using an expression===
or!==
will always evaluate totrue
.checkFunctionNameCase
– Ensures that function names are capitalized with their definition when called across the codebase.polluteScopeWithLoopInitialAssignments
– If set tofalse
(hertrue
default), variables declared in initial loop statements (eg$i
in$for ($i = 1; $i < 10; $i++)
) cannot be accessed outside of the loop's code block, avoiding possible contamination of the parent scope.reportStaticMethodSignatures
- Enforces full type checking for parameters and return types in static methods when overridden by a child class.
Full details on these optional settings - and much more - can be found in the PHPStan configuration reference.
Conclusion
That's the end of our introduction to PHPStan. It helps you feel confident about your codebase and points out potential issues before they become a problem in production.
PHPStan is so quick to set up that there's really no reason not to use it, especially if you're running a modern, highly typed codebase. However, don't be fooled into thinking that it can replace manual testing. PHPStan boasts a wide range of controls, but it cannot identify logical problems and does not understand the business rules of your project. It's just another asset in your toolbox when assessing the health of a codebase, in addition to trusted guides such as unit tests and end-to-end functionality tests.
Source link