Testing your code is one way to ensure that you have a high quality codebase, which is one way to ensure the maintainability of your projects and also a way to ensure you don't ship broken features in your product. CI tools like Travis CI help you to test your code each time you push to source control.
Static analysis is the method of testing your code for basic logical, runtime or typographical exceptions without actually executing the code.
As you must have guessed, static analysis of your codebase happens fast since the code doesn't actually get executed but scanned for common errors like having a method that doesn't return the expected date type.
How static analysis works
Static analysis as the name implies, actually doesn't need to execute your code before catching bugs in them. Statically typed languages like Dart or Java already have this functionality built into their compilers. Since they always define the types
of their constructs the compiler won't run when there is a typo or an incorrect type for a method or variable. Before the advent of static analysis and tools like PHPStan, developers spend a lot of time debugging their PHP code looking for errors because PHP's execution is line by line and so it only throws an error when it gets to the line containing the error. And may sometimes continue execution after encountering the error, depending on the type of error encountered.
PHPStan checks for a couple of language constructs such as use of instanceof
, try-catch
blocks, typehints
, number of arguments passed to a function, accessibility of called methods and variables, and many more.
PHPStan: Static analysis in your favourite language
Recently, PHPStan Pro was announced by the creators of PHPStan and that is already looking very promising with continuous watch mode (hot-reloading in PHP?), a Web UI and an interactive fixer! The good news is you get to save a ton of time and keystrokes by finding errors sooner and PHPStan can suggest a fix for you and everyone is happier.
Using PHPStan in your projects
Below we will go over steps to use PHPStan in our projects.
Setting up your environment
You can use PHPStan in any PHP project of your choice, for the purpose of this tutorial I have created a skeleton PHP library that I will be using. My composer.json
file looks like this before installing phpstan
A screenshot of my composer.json setup
Installing PHPStan as a dev dependency
composer require --dev phpstan/phpstan
We are installing phpstan
as a dev dependency with composer.
Now you are ready to run your first analysis, copy and paste the code below in your terminal:
phpstan analyse src
Depending on the content of your src
directory you may get some errors after running this command and that is totally fine as we will look at how to configure PHPStan to our taste soon.
phpstan Command
The analyse
keyword is what tells phpstan
to analyse your codebase, and the 3rd argument in the command is the path to the code you want to analyse. Here I have used src
as that is where the code I have written lives, I do not need to analyse my vendor folder or other temporary folders. However if you are writing tests then it's a good idea to analyse your tests
directory as well. PHPStan has some extensions for popular testing libraries like PHPUnit, Behat and mock frameworks like Mockery.
Configuration
PHPStan makes use of the neon
file format for its configuration, ideally you will have a phpstan.neon
at the root of your project folder. Whenever you run the phpstan analyse
command, it will look for phpstan.neon
at the root and use it as configuration to analyse your code. If it doesn't find the configuration file at the root of your project, PHPStan will also check for phpstan.neon.dist
and if that doesn't exist as well, it will run with the default configs. Below is a basic configuration options to get you started. Read more here.
parameters:
level: max
paths:
- src
- test
Using the configuration setting above, we can now omit the 3rd argument when running the phpstan
command which is the path
to our source code. This is now a valid command once you have phpstan.neon
on your root directory:
phpstan analyse
With the level
set to max, we have more stricter analysis and things like incorrect typehints, incorrect return types, will now throw an error:
$ phpstan analyse
Note: Using configuration file Code\demo\photo-library\phpstan.neon.
1/1 [============================] 100%
------ ----------------------------------------------------------------------------------------
Line Photo.php
------ ----------------------------------------------------------------------------------------
7 Property Photo::$http has no typehint specified.
9 Method Photo::__construct() has parameter $token with no typehint specified.
25 Method Photo::photos() return type has no value type specified in iterable type array.
๐ก Consider adding something like array<Foo> to the PHPDoc.
You can turn off this check by setting checkMissingIterableValueType: false in your
Code\demo\photo-library\phpstan.neon.
27 Method Photo::photos() should return array but returns string.
------ ----------------------------------------------------------------------------------------
Take note of this line which now tells us that our configuration file is being used to analyse our code:
Note: Using configuration file Code\demo\photo-library\phpstan.neon.
The code which produced the errors above looks like this:
<?php
declare(strict_types=1);
use GuzzleHttp\Client;
class Photo{
private $http;
public function __construct(string $token)
{
$this->http = new GuzzleHttp\Client([
'base_uri' => 'https://photo.google.com',
'headers' => [
'Authorization' => 'Bearer ' . $token
]
]);
}
/**
* Returns an array of photos in the
* library
*
* @return array
*/
public function photos(): array
{
return 'Photos in the library';
}
}
Since my codebase above is relatively new and I am using PHP 7.4 with strict types enabled, I may have better luck resolving these errors in a few minutes. That may not be the case when you have a large codebase, and you don't have to feel bad for having these errors since you wrote the code without static analysis in mind.
Editing our phpstan.neon
file and setting the level
to anywhere between 0 and 8 will allow us to make a loose or strict analysis based on the level we settle for. The max
level will use the strictest value available depending on the version of PHPStan you have. Learn more about the levels here
Nip it in the bug :)
Catch your bugs before they get bigger and cause problems. One way I love to do this is by adding phpstan to the scripts section of my composer.json
and running a command to analyse my codebase before pushing to source control. You can also add phpstan
to your travis ci builds and we will see how to do that in a bit.
Add the following to the scripts section of your composer.json:
"scripts": {
"analyse": [
"phpstan analyse src -c phpstan.neon --level max --no-progress",
"phpstan analyse tests -c phpstan.neon --level 4 --no-progress"
],
}
This adds a script called analyse
to composer which you can run by executing composer run analyse
. That will execute the 2 commands we have specified here:
"phpstan analyse src -c phpstan.neon --level 5 --no-progress"
"phpstan analyse tests -c phpstan.neon --level 5 --no-progress"
The first command analyses our src
directory and the second analyses the tests
directory. We are passing a couple of arguments which you can almost already tell what they do:
- -c phpstan.neon: Tells phpstan to run with the configurations defined in phpstan.neon
- โlevel: Tells phpstan what level to run the analysis at (5 in this case)
- โno-progress is a special flag to tell phpstan not to report analysis progress as it traverses our codebase.
Adding phpstan to your Travis builds
This can be achieved by adding the composer script to analyse our codebase in the script section of .travis.yml
:
script:
- composer run analyse
This is only for demonstration purpose, ideally you will want to run other checks which you can group into a composer script in your composer.json file and run that script in your travis build but this is meant to give you an overview of how that is done.
You can find a sample .travis.yaml
which I use here for my builds here and a sample composer.json file here
Final notes
Static analysis is something I learned recently and I must say that it gives a unique developer experience. As I am able to write efficient and clean code and catch my errors before they make it to source control. I hope that this article has given you an insight on how static analysis can help you write better code and improve your development process. Please leave your thoughts and comments on Twitter.
Top comments (0)