PHPStan static code analyzer for Magento 2

PHPStan static code analyzer for Magento 2

It happens to everybody you make a quick change. it's a small change so you don't test it, you push the change to staging or to live (I hope not) and inform the customer of the change. And then the customer calls you that the change doesn't not work or worse that the whole page/website doesn't work. You look op the code and see an obvious error that will never work like a typo and you fix this and inform the customer. Yes you needed to test it first or better have tests that will run on every build, but this is the real world with budgets and deadlines so the first thing that will go are tests.

If you where programming in a compiled language like C, Java or C#, the compiler will find this kind of errors and you could never build and deploy your application. Only with dynamic languages like PHP, Pyhton or Ruby, you will find this error on runtime when its to late. Lucky there are static analyzer tools like PHPStan that will help you with this.

PHPStan

PHPStan is a code analyzer tool that analyze your code without running it to find bugs even before you write tests for the code. PHPStan moves PHP closer to compiled languages in the sense that the correctness of each line of the code can be checked before you run the actual line.

Sounds awesome lets use it to catch errors in our Magento 2 modules. Not so fast, because Magento 2 is a complex code base PHPStan wont work out of the box with Magento 2. But don't worry at the end of this blog you will have PHPStan working with Magento 2.

PHPStan with Magento 2

When running PHPStan it will automatically load the vendor autoload file if it finds the vendor folder. Only with this it wont find your classes in app/code, you can solve this by using the --autoload-file parameter and supply it with the Magento 2 app/bootstrap.php. But now you run in the following problem that it cant find Factory classes because these are generated by Magento 2.

To solve this you need to create a custom bootstrap file that will include the Magento 2 bootstrap file and register a custom autoload function that will try to get the class with the Magento 2 ObjectManager:

<?php

/* Find bootstrap path */
$rootPath = realpath(dirname(__FILE__));
while (!file_exists($rootPath . '/app/bootstrap.php') || $rootPath == '/') {
    $rootPath = realpath(dirname($rootPath));
}

/* Include Magento bootstrap file */
require_once $rootPath . '/app/bootstrap.php';

/* Create git hook class autoloader */
$_git_hook_loaded_class = [];
function phpstan_magento2_autoloader($class) {
    global $_git_hook_loaded_class;
    if(isset($_git_hook_loaded_class[$class])) {
        return $_git_hook_loaded_class[$class];
    }

    try {
        /* Get Magento ObjectManager */
        $bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER);
        $objectManager  = $bootstrap->getObjectManager();

        $objectManager->get($class);
        $_git_hook_loaded_class[$class] = true;
    } catch(\Exception $e) {
        $_git_hook_loaded_class[$class] = false;
    }

    return $_git_hook_loaded_class[$class];
}
spl_autoload_register('phpstan_magento2_autoloader');

Magic methods

Now you have PHPStan working with Magento 2 you will get errors for magic methods because PHPstan cant find these function. PHPStan has a configuation option to ignore errors based on regular expression. The PHPStan config uses the neon file format and can be supplyed to PHPStan with the -c parameter, the config file for ignoring the standard magic methods:

parameters:
    ignoreErrors:
        - '#Call to an undefined method [a-zA-Z0-9\\_]+::(get|set|uns|has)[A-Z]#'

Validating phtml files

To make PHPStan work with Magento 2 phtml files will take more work. You need to annotate $block and $this, but standard PHPStan wont uses this annotation to check for these reference. You need to change PHPStan and compile to phar file yourself to make this work, Lucky for you I already have done this and also create a phar file you can download.

After you download te altered version of PHPStan you need to update the neon config file to ignore errors for $this outside a class:

parameters:
    ignoreErrors:
        - '#Call to an undefined method [a-zA-Z0-9\\_]+::(get|set|uns|has)[A-Z]#'
        - '#Using \$this outside a class#'
    fileExtensions:
        - php
        - phtml

And phtml files must have annotation at the beginning of the file for $block or/and $this when used in phtml file:

<?php /* 
 * @var \<full path of class> $block 
 * @var \Magento\Framework\View\TemplateEngine\Php $this
 */ ?>

Running PHPStan

So putting this all together you will have an altered version of PHPstan downloaded that will work with Magento 2. You will have a custom PHPStan bootstrap file and configuration file in your project. Now you can finnaly run PHPStan for your project with this command:

phpstanM2.phar analyse --level=4 --autoload-file=dev/tools/phpstan/bootstrap.php -c dev/tools/phpstan/config.neon <files and folders you want to analyze>

Improve code quality

To make PHPStan more acquired you need to annotade all the code so PHPStan can undersand your code better. So together lets improve the code quality of Magento 2 modules by using PHPstan and annotade all code.

Previous Post Translating python gtk builder files

There are no comments yet.

Leave a Comment

You may format you comment with Markdown.