DEV Community

Cover image for How I take care of code quality with GrumPHP
Adrian M
Adrian M

Posted on

How I take care of code quality with GrumPHP

Everyone knows how important is taking care of code quality in our projects. There's a lot of ways to do that - code reviews, code standards or unit tests. Some responsibilities can be handled by some static analysis tools. I'm pretty sure you have heard about PHPStan, PHP Code Sniffer or PHPMD. Configuration of each in the project might be awkward.

GrumPHP keeps all-in-one configuration for all most popular tools. "This composer plugin will register some git hooks in your package repository. When somebody commits changes, GrumPHP will run some tests on the committed code". The library has a lot of built-in tasks and you can start using them with few lines of configuration.

I would like to show you how to implement GrumPHP in project. So, let's get started.

(TL;DR version can be found at the end of the article)

GrumPHP installation

Go to your project, open a terminal and install GrumPHP via composer command

composer require --dev phpro/grumphp
Enter fullscreen mode Exit fullscreen mode

When composer asks you to create a grumphp.yml file

Do you want to create a grumphp.yml file? [Yes]:
Enter fullscreen mode Exit fullscreen mode

just type No, we’re going to create the configuration manually.

Watch out! GrumPHP is sniffing your commits!
Enter fullscreen mode Exit fullscreen mode

Good, looks like the package is installed.

GrumPHP configuration

To start using GrumPHP we need grumphp.yml file. Let's create that file with minimal configuration in root directory of your project.

# grumphp.yml

grumphp:
  tasks:
Enter fullscreen mode Exit fullscreen mode

As I mentioned before, GrumPHP is run on every single commit. But there is a way to run checks manually when needed. Let's just run binary file from a composer vendor

./vendor/bin/grumphp run
Enter fullscreen mode Exit fullscreen mode

In the terminal you should noticed a grummy man's face. He will supervise your code quality, so watch out!

             ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
           ▄▄▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌           
         ▄▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
        ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
        ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌        
  ▄▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
 ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌        
 ▐█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌        
   ▀█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌        
     ▀▀▓▓▓▓▓▓▓▓▓▓▓▓█▀▀▀▀▀▀▀▀▀▀▀▀▀▀████████████▄
      ▄████████▀▀▀▀▀                 ██████████   
     ███████▀                         ██████▀
      ▐████      ██▌          ██       ████▌      
        ▐█▌                            ███        
         █▌           ▄▄ ▄▄           ▐███        
        ███       ▄▄▄▄▄▄▄▄▄▄▄▄       ▐███         
         ██▄ ▐███████████████████████████
        █▀█████████▌▀▀▀▀▀▀▀▀▀██████████▌▐         
          ███████████▄▄▄▄▄▄▄███████████▌          
         ▐█████████████████████████████           
          █████████████████████████████           
           ██ █████████████████████▐██▀           
            ▀ ▐███████████████████▌ ▐▀            
                ████▀████████▀▐███                
                 ▀█▌  ▐█████  ▐█▌                 
                        ██▀   ▐▀                  
       _    _ _                         _ _
      / \  | | |   __ _  ___   ___   __| | |
     / _ \ | | |  / _` |/ _ \ / _ \ / _` | |
    / ___ \| | | | (_| | (_) | (_) | (_| |_|
   /_/   \_\_|_|  \__, |\___/ \___/ \__,_(_)
                  |___/
Enter fullscreen mode Exit fullscreen mode

Ok, now we can setup some tasks and checks.

PHP CodeSniffer (PHPCS)

What is PHP CodeSniffer?

PHP_CodeSniffer tokenizes PHP files and detects violations of a defined set of coding standards.

Let's install required dependency with the composer

composer require --dev squizlabs/php_codesniffer
Enter fullscreen mode Exit fullscreen mode

Based on PSR, currently PSR-12 is a recommended coding standard.

Let's add PHP CodeSniffer task and determine standard in our configuration file.

# grumphp.yml

grumphp:
  tasks:
    phpcs:
      standard: PSR12
Enter fullscreen mode Exit fullscreen mode

Now, commit your changes (or run manually GrumPHP) to check your code for the first time.

Oops... GrumpPHP found some issues related to PSR12 standard so take a look on a message that points the file and brings more information about the error.

FILE: .../src/User.php
---------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
---------------------------------------------------------------
 27 | ERROR | [x] Expected 1 newline at end of file; 0 found
--------------------------------------------------------------------

I can fix some stuff automatically, do you want me to? (yes/no) [no]:
Enter fullscreen mode Exit fullscreen mode

There are two options to resolve these errors:

  • go to the file and fix them manually, or
  • trust GrumPHP and allow it to fix them automatically. To do so type yes in the terminal.
Auto-Fixing tasks...
Running fixer 1/1: phpcs... ✔

[WARNING] Please review the code changes that I made!
Enter fullscreen mode Exit fullscreen mode

Remember, you should review all the changes made by the tool.

Great! Now the project is consistent with PSR12 standard, that’s a good start.

PHPStan

The PHPStan task focuses on finding errors in your code without actually running it. It catches whole classes of bugs even before you write tests for the code

Install a required dependency by running the composer command

composer require --dev phpstan/phpstan
Enter fullscreen mode Exit fullscreen mode

Next, add PHPStan as one of tasks in the configuration file

# grumphp.yml

grumphp:
  tasks:
    phpcs:
      standard: PSR12
    phpstan:
      level: 5
Enter fullscreen mode Exit fullscreen mode

There are 9 levels of checks from 0 to 8, where 0 is the loosest and 8 is the strictest. Which one should you choose? It depends.

If you are working with a legacy code or you are just starting to take care of your code quality - choose between 0 and 3. You can always upgrade the level in the future.

When you are confident with your codebase and skills then I recommend choosing levels from 4 to 8.

Run GrumPHP. If there are some errors, you will see a message that may look like this

phpstan
=======

----------- -------------------------------------------------------------------- 
  Line   src/User.php                                                        
 ------ -------------------------------------------------------------------- 
  21     Method User::id() should return string but returns int.  
 ------ --------------------------------------------------------------------
Enter fullscreen mode Exit fullscreen mode

Unfortunately, all the fixes have to be done manually.

It looking good, we have installed two tasks already.

PHPUnit

(If you don’t use PHPUnit in your project, skip this section)

I used to forgot running tests before committing my changes. Sometimes after that, a build on my pipeline failed.

To be sure unit tests always pass, let's add PHPUnit task to GrumPHP.

# grumphp.yml

grumphp:
  tasks:
    phpcs:
      standard: PSR12
    phpstan:
      level: 5
    phpunit:
      always_execute: true
Enter fullscreen mode Exit fullscreen mode

Because as a rule unit tests are executed really fast, set always_execute as true. It means unit test will be run on every commit. Thanks to that, if any test fails, GrumPHP will inform us about that incident.

phpunit
=======

PHPUnit 9.X.X by Sebastian Bergmann and contributors.

...

FAILURES!
Tests: 2, Assertions: 2, Failures: 1.
Enter fullscreen mode Exit fullscreen mode

I would like to show you one more interesting and useful tool.

Security Checker

Nowadays, everyone uses the composer and external dependencies. Libraries very often become affected by vulnerabilities and it's difficult to track changelog of them all.

GrumPHP and Security Checker can help to detect dangerous packages you use.

The Security Checker will check your composer.lock file for known security vulnerabilities.

Let's install the required dependency

composer require --dev enlightn/security-checker
Enter fullscreen mode Exit fullscreen mode

Add task to grumphp.yml file and set run_always: true flag. It means that on every commit all dependencies will be checked by tool.

# grumphp.yml

grumphp:
  tasks:
    phpcs:
      standard: PSR12
    phpstan:
      level: 5
    phpunit:
      always_execute: true
    securitychecker:
      run_always: true
Enter fullscreen mode Exit fullscreen mode

Run GrumPHP and check the result.

securitychecker
===============

Symfony Security Check Report
=============================

1 packages have known vulnerabilities.

guzzlehttp/guzzle (6.2.0)
------------------------------

 * [CVE-2016-5385][]: HTTP Proxy header vulnerability

[CVE-2016-5385]: https://github.com/guzzle/guzzle/releases/tag/6.2.1
Enter fullscreen mode Exit fullscreen mode

As you can see above, there is pointed package with vulnerability that have to be updated.

Summary

All looks good, four tasks passed successfully. It's a good first step towards better code quality in your project.

Running task 1/4: phpcs... ✔
Running task 2/4: phpstan... ✔
Running task 3/4: phpunit... ✔
Running task 4/4: securitychecker... ✔
             ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
           ▄▄▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌           
         ▄▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
        ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
        ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌        
  ▄▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
 ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌        
 ▐█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌        
   ▀█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌        
     ▀▀▓▓▓▓▓▓▓▓▓▓▓▓█▀▀▀▀▀▀▀▀▀▀▀▀▀▀████████████▄
      ▄████████▀▀▀▀▀                 ██████████   
     ███████▀                         ██████▀
      ▐████      ██▌          ██       ████▌      
        ▐█▌                            ███        
         █▌           ▄▄ ▄▄           ▐███        
        ███       ▄▄▄▄▄▄▄▄▄▄▄▄       ▐███         
         ██▄ ▐███████████████████████████
        █▀█████████▌▀▀▀▀▀▀▀▀▀██████████▌▐         
          ███████████▄▄▄▄▄▄▄███████████▌          
         ▐█████████████████████████████           
          █████████████████████████████           
           ██ █████████████████████▐██▀           
            ▀ ▐███████████████████▌ ▐▀            
                ████▀████████▀▐███                
                 ▀█▌  ▐█████  ▐█▌                 
                        ██▀   ▐▀                  
       _    _ _                         _ _
      / \  | | |   __ _  ___   ___   __| | |
     / _ \ | | |  / _` |/ _ \ / _ \ / _` | |
    / ___ \| | | | (_| | (_) | (_) | (_| |_|
   /_/   \_\_|_|  \__, |\___/ \___/ \__,_(_)
                  |___/

Enter fullscreen mode Exit fullscreen mode

I have introduced you to GrumPHP with a really simple configuration. There is a lot of different tasks that you can use in your project and full list can be found in official GitHub repository: GrumPHP Task Docs.

TL;DR

Install GrumPHP:

composer require --dev phpro/grumphp
Do you want to create a grumphp.yml file? [Yes]:
> No
Enter fullscreen mode Exit fullscreen mode

Install dependencies

composer require --dev squizlabs/php_codesniffer
composer require --dev phpstan/phpstan
composer require --dev enlightn/security-checker
Enter fullscreen mode Exit fullscreen mode

Create a file grumphp.yml in the project's root directory with the following configuration:

# grumphp.yml

grumphp:
  tasks:
    phpcs:
      standard: PSR12       # PSR12 is recommended, but there are available i.a. PSR1, PSR2
    phpstan:
      level: 5              # levels: 0-8, where 0 is the loosest and 8 is the strictest
    phpunit:                # comment those lines if you ...
      always_execute: true  # ... don't use PHPUnit in your project
    securitychecker:
      run_always: true
Enter fullscreen mode Exit fullscreen mode

Commit changes or just run binary file from the composer vendor

./vendor/bin/grumphp run
Enter fullscreen mode Exit fullscreen mode

More build-in tasks can be found in official GitHub repository: GrumPHP Task Docs

Top comments (1)

Collapse
 
syntaxseed profile image
SyntaxSeed (Sherri W)

I have been toying with the idea of building something to gather all my code analysis tools under 1 umbrella... then lo & behold I read your article. GrumPHP does exactly this.

Awesome, thanks for writing about this! 👍