قالب وردپرس درنا توس
Home / Tips and Tricks / How to statically analyze PHP projects with PHPStan – CloudSavvy IT

How to statically analyze PHP projects with PHPStan – CloudSavvy IT



PHPStan logo

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̵

7;s built-in introspective capabilities to analyze your project.

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.

A successful PHPStan run

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.

A failed PHPStan run

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 of instanceof which will always evaluate to true.
  • checkAlwaysTrueStrictComparison – Flags when using an expression === or !== will always evaluate to true.
  • checkFunctionNameCase – Ensures that function names are capitalized with their definition when called across the codebase.
  • polluteScopeWithLoopInitialAssignments – If set to false (her true 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