Static Analysis in Magento with PHPStan

Learn about PHPStan and a related Magento plugin, which provide the ability to help follow Magento best practices by analyzing code during development.

Mark Shust

Mark Shust

6 min read

What is PHPStan?

PHPStan is a static analyzer for PHP. A static analyzer is a sort of program that can check & find errors in your code, without actually executing that code. This can help you catch bugs in your code at the time you are typing it out.

PHPStan logo

There are other code analyzers available, the most popular one being PHP_CodeSniffer. While this tool is still very useful to make sure code is properly formatted, PHPCS can only check one file at a time.

Due to this restriction, it is not able to perform more advanced inspections that may trace back to parent classes or referenced types. You will also probably want more advanced analysis of your code, given the dynamic nature of PHP programs (especially ones as large as Magento).

Upgrade to PHPStan 1.6 for Magento Support

First off... did you know that Magento actually comes with PHPStan pre-installed? You can confirm this by checking out the composer.json file in the root of your Magento instance:

Composer.json file containing PHPStan as a dependency

You will notice that on the latest version of Magento at the time of this writing (2.4.4), the version the phpstan/phpstan package is set to ~1.2.0. This designation basically means it supports any version >=1.2.0 <1.3.0. However, the most recent version of PHPStan at the time of this writing is 1.6.8.

To confirm which version of PHPStan you are really running, execute:

composer show phpstan/phpstan

Looking at the versions property, we can confirm that we are currently at 1.2.0:

Result of running composer show phpstan/phpstan

Let's update this Composer package. I’ve found the easiest way to update a specific package is to basically install it again with require:

composer require --dev phpstan/phpstan

This line is not that invasive and usually runs pretty smoothly. Not only will this update the Composer package you specify, but also it’s related version in the composer.json file:

Result of running composer require phpstan/phpstan

The related composer.lock file will also keep the specific version of PHPStan pegged to whatever version was installed at the time you executed the composer require line above. This ensures a version of this package doesn’t “bump” without you knowing about it.

Install the PHPStan Magento Plugin

While you can execute the PHPStan CLI whenever you wish, you’ll almost always want to add a configuration that adds specifics about the framework you are working on; in this case, Magento. Magento is an extremely intricately written piece of software, so adding this type of plugin is pretty much mandatory if you wish to use PHPStan with Magento.

Stephan Hochdörfer of bitExpert has been a long-time Magento developer, and is also the lead author of a project which offers this Magento-specific PHPStan configuration.

Thanks Stephan! 🤗

This configuration is available on GitHub at bitexpert/phpstan-magento:

bitexpert/phpstan-magento GitHub repo

To install this package, all you need to do is run:

composer require --dev bitexpert/phpstan-magento

This installs the PHPStan Magento plugin as a Composer dev dependency. Dev dependencies are pretty neat because they eliminate the need to install these dependencies on production, saving disk space while also simultaneously speeding up deployments.

Register the Magento plugin with PHPStan

While we just installed the Magento plugin, PHPStan doesn’t yet know it exists. The easiest way to make it aware of this module is by installing the PHPStan Extension Installer. This package automatically registers third-party PHPStan plugins so that PHPStan can be made immediately aware of them.

To install this extension installer, just run the line:

composer require --dev phpstan/extension-installer

Note that Composer 2 introduced additional security checks for those packages that are considered “Composer Plugins”. This will cause a “trust” dialog to prompt you to enable it as an “allowed plugin”:

Composer allow-plugins prompt

You can type y to continue through this prompt.

If you wish to have an automated install without this prompt, you can also manually define the extension-installer package as an allowed Composer plugin by executing this command line before attempting to install it:

composer config allow-plugins.phpstan/extension-installer true

This will prevent the prompt from ever occurring, manually adding a property to the allow-plugins object in the composer.json file:

Composer config allow-plugins result

Now whenever we execute PHPStan, it will automatically use this related Magento plugin when analyzing code, along with any others we may install.

Stumped on the hardest part of Magento?

Executing PHPStan for Magento

Now that PHPStan and the related Magento plugin are installed, we can execute it with:

vendor/bin/phpstan analyse DIRECTORY_TO_EXECUTE

For example, since I want to check the code of my Composer-installed DisableTwoFactorAuth module, I can execute:

vendor/bin/phpstan analyse vendor/markshust/magento2-module-disabletwofactorauth

Look ma, no errors! 🎉

PHPStan no errors result

PHPStan contains a really passive initial level though, and allows you to control the verbosity of its analysis with the --level argument, all the way from 0 to 9. These are called Rule Levels, and you can check out all of the available rule levels & what they entail.

For example, I added a --level flag set to 9, specifying a single file to check, and immediately got 2 errors returned 😬:

PHPStan errors result

What’s your take?

We're just beginning to see how powerful PHPStan can be. Taking it a step further, you can look into integrating PHPStan into your own Magento deployment pipeline.

And if you’re up to the task, you can even create your custom ruleset or extension that is specific to your needs as a Magento developer, just as Stephan did!

Want to get notified when new Magento blogs are published?

Blog feed reader? Grab the RSS Feed URL