Software projects and static code analysis
Testing pays off, no doubt about it. It gives you confidence that the feature you add does not accidentally break the existing product.
It comes with a caveat, though. How much testing is enough? How much time should you spend on writing tests? The test code is still code, and while it provides confidence and stability, it can incur development costs. Covering all possible scenarios might just not be worth it.
This is where static analysis tools come in handy. These are tools that offer many benefits, while being extremely easy to use. (You’ll be pleasantly surprised!) In many cases, setting them up is quick: you install the tool with Composer and call it, pointing it to the directory that you want to analyze.
At Ibexa, our static analysis tool of choice is PHPStan. Its direct competitor, Psalm, has a similar feature set, and numerous checks make their way from one library to the other, so feel free to pick whichever you prefer.
Adding PHPStan to your project
To install PHPStan with Composer, run:
composer require --dev phpstan/phpstan
To have it analyze your code, run:
composer exec phpstan analyse src/ -- --level=0
Naturally, if you have more directories to analyze or want to apply greater strictness, you can modify the settings accordingly. (The first double dash separates Composer options from PHPStan ones, that’s a Composer feature. Also, depending on how your Composer is configured, you can also call vendor/bin/phpstan directly, or bin/phpstan.)
If you are happy with static analysis results and decide to stick with it, you might want to add a configuration file, so that you do not have to pass the options manually each time.
Once PHPStan is installed (using either the procedure above or by following the instructions on PHPStan’s website), you will most likely run analysis at strictness level 0. At this level the most basic issues are checked, like whether your code syntax is correct, the methods you call do exist, or if you are passing the right arguments.
Review the errors that PHPStan reports. Check them out, it could be something simple. You might end up with adding a proper description to the variable.
If none of the errors raises your immediate concern, you can repeat the scan at a more restrictive level. For a detailed description of strictness levels, see PHPStan docs.
Finally, create the configuration file, and run PHPStan again, ordering it to create a baseline file. This way the remaining errors are recorded and do not prevent you from carrying on with your work:
composer exec phpstan analyse -- --generate-baseline
PHPStan has gathered an active community of users. One of their recommendations is that you use the highest level of strictness you’re comfortable with. This will help ensure that new code follows the standards that you’ve set for yourself.
So, what’s in it for me?
No null check is left behind, no type is left undefined. When dealing with arrays of data, PHPStan ensures that you’re always using the right data. When a method returns iterable, you know what is inside of it (from the description) and remember to convert it into array if needed (instead of accidentally using an array, just because of how it was done in the current implementation.)
PHPStan helped Ibexa massively increase the quality of the code. It acted like a second pair of eyes reviewing the code and spotting issues that might have been missed. In core Ibexa code, it detected instances of incorrect declarations in PHPDoc, missing property declarations, and much more.
PHPStan detected a method call, which slipped through automatic tests. It was invalid under certain conditions.
Our review process for new code got simplified, because PHPStan immediately spots basic errors, without the need for developers to scan the code manually. This way we can focus on developing the actual features.
All of our newest packages are analyzed with the highest strictness level, and older ones with the highest level possible. We will be upgrading these as time allows, so that all our APIs are well described. Eventually, you will be using them in the full confidence that your code is future-proof, just as we do when doing cross-package work.
When working with PHPStan, you can install extensions that enhance the capabilities of the static analyser. For Symfony projects, you might want to install phpstan/phpstan-symfony extension. (You do it with Composer, just like any other package.) You could also benefit from other extensions, such as Doctrine or PHPUnit. Extensions usually add library-specific information for static analysis tools to pick up. For example, Symfony extension features include fixing configuration tree builder definitions and providing form transformer information.
There's no need to say that I highly recommend that you use static analysis. It is an immensely helpful tool. You can apply it to your existing codebase, pick a level you’re comfortable with, and be rest assured that your new code is well written, with all the basics covered.
At Ibexa we discovered numerous hard-to-spot errors this way, mos of which had slipped through the most stringent integration tests.
Stay tuned for future blog posts which will cover an array of advanced features that come with PHPStan, like generics and their templates. In the meantime to learn more about Ibexa, check out our Developer Portal.