Static Analyzers for PHP were the topic of Episode 73 of the PHP Roundtable podcast (June 12, 2018), with a panel of folks who have been building these code-checking, bug-finding tools.  The basic idea is that these tools bring the analysis techniques usually found in strong typed languages and compilers to PHP.

A static analyzer is a program that examines the code without executing it, and looks for problems in the code.  Examples of problems that can be found by these tools are unused or uninitialized variables, unused function arguments, and many more complicated issues.

There are ways to include Static Analysis into Continuous Integration workflows, or to integrate it with your code editor or IDE to make Static Analysis just a keystroke away.

The idea of being able to find bugs in my code without even running it sounds pretty good, so I tried out one of the tools mentioned in the podcast, PHPstan by Ondřej Mirtes, one of the panelists.  

PHPstan is available from https://github.com/phpstan/phpstan which describes the many checks the tool can perform on your code, including (from the beginning of the documentation’s list):

  • Existence of classes and interfaces in instanceof, catch, typehints, other language constructs and even annotations. PHP does not do this and just stays silent instead.
  • Existence of variables while respecting scopes of branches and loops.
  • Existence and visibility of called methods and functions.
  • Existence and visibility of accessed properties and constants.
  • Correct types assigned to properties.

To give PHPstan a spin, I cloned on of our Laravel projects into a new directory and installed PHPstan into the working directory:

$ cd testproject
$ composer require --dev phpstan/phpstan

This is a Laravel project, so I have my controllers in app/Http/Controllers.   I can check these files with

vendor/bin/phpstan analyse app/Http/Controllers

In my example, phpstan found 108 errors, many like this:

55     Call to an undefined static method App\Service::where().
77     Call to static method route() on an unknown class Redirect.
81     Call to an undefined static method App\Service::create().
108    Call to an undefined static method App\OwningOrg::orderBy().

It’s apparent that phpstan is not understanding dependencies that are part of the Laravel framework.  A little reading revealed there is a Laravel-specific plugin for phpstan, so I gave that an install:

$ composer require --dev weebly/phpstan-laravel

The plugin also requires creating a phpstan.neon configuration file and adding a couple of lines:

includes:
 - vendor/weebly/phpstan-laravel/extension.neon

The analysis command now becomes:

vendor/bin/phpstan analyse -c phpstan.neon --level 1 app/Http/Controllers

This brought the initial number of issues down to 22, with examples like:

 187    Variable $result might not be defined.
 150    Return typehint of method App\Service::getServiceManagers() has invalid type App\collection.
 152    Access to an undefined property App\Service::$products.

Changing the –level parameter changes the number of rules that are checked, for example I see that level 2 checks PHPDocs syntax whereas level 1 does not.

Even with the Laravel plugin, there are still some things that look like misunderstood Laravel constructs… luckily the docs show it is easy to suppress unwanted error messages with regular expression based rules.

This only scratches the surface of PHPstan.  It may take some tuning to make this a valuable tool.  And it’s only useful if you actually use it, so integrating the run into a continuous integration script seems the best way to assure that it actually gets used.

Check out the podcast for lots more on the topic and other tools in the PHP static analyser space.