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
When composer asks you to create a grumphp.yml
file
Do you want to create a grumphp.yml file? [Yes]:
just type No
, we’re going to create the configuration manually.
Watch out! GrumPHP is sniffing your commits!
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:
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
In the terminal you should noticed a grummy man's face. He will supervise your code quality, so watch out!
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▄▄▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
▄▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
▄▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
▐█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
▀█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
▀▀▓▓▓▓▓▓▓▓▓▓▓▓█▀▀▀▀▀▀▀▀▀▀▀▀▀▀████████████▄
▄████████▀▀▀▀▀ ██████████
███████▀ ██████▀
▐████ ██▌ ██ ████▌
▐█▌ ███
█▌ ▄▄ ▄▄ ▐███
███ ▄▄▄▄▄▄▄▄▄▄▄▄ ▐███
██▄ ▐███████████████████████████
█▀█████████▌▀▀▀▀▀▀▀▀▀██████████▌▐
███████████▄▄▄▄▄▄▄███████████▌
▐█████████████████████████████
█████████████████████████████
██ █████████████████████▐██▀
▀ ▐███████████████████▌ ▐▀
████▀████████▀▐███
▀█▌ ▐█████ ▐█▌
██▀ ▐▀
_ _ _ _ _
/ \ | | | __ _ ___ ___ __| | |
/ _ \ | | | / _` |/ _ \ / _ \ / _` | |
/ ___ \| | | | (_| | (_) | (_) | (_| |_|
/_/ \_\_|_| \__, |\___/ \___/ \__,_(_)
|___/
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
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
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]:
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!
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
Next, add PHPStan as one of tasks in the configuration file
# grumphp.yml
grumphp:
tasks:
phpcs:
standard: PSR12
phpstan:
level: 5
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.
------ --------------------------------------------------------------------
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
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.
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
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
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
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... ✔
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▄▄▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
▄▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
▄▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
▐█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
▀█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌
▀▀▓▓▓▓▓▓▓▓▓▓▓▓█▀▀▀▀▀▀▀▀▀▀▀▀▀▀████████████▄
▄████████▀▀▀▀▀ ██████████
███████▀ ██████▀
▐████ ██▌ ██ ████▌
▐█▌ ███
█▌ ▄▄ ▄▄ ▐███
███ ▄▄▄▄▄▄▄▄▄▄▄▄ ▐███
██▄ ▐███████████████████████████
█▀█████████▌▀▀▀▀▀▀▀▀▀██████████▌▐
███████████▄▄▄▄▄▄▄███████████▌
▐█████████████████████████████
█████████████████████████████
██ █████████████████████▐██▀
▀ ▐███████████████████▌ ▐▀
████▀████████▀▐███
▀█▌ ▐█████ ▐█▌
██▀ ▐▀
_ _ _ _ _
/ \ | | | __ _ ___ ___ __| | |
/ _ \ | | | / _` |/ _ \ / _ \ / _` | |
/ ___ \| | | | (_| | (_) | (_) | (_| |_|
/_/ \_\_|_| \__, |\___/ \___/ \__,_(_)
|___/
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
Install dependencies
composer require --dev squizlabs/php_codesniffer
composer require --dev phpstan/phpstan
composer require --dev enlightn/security-checker
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
Commit changes or just run binary file from the composer vendor
./vendor/bin/grumphp run
More build-in tasks can be found in official GitHub repository: GrumPHP Task Docs
Top comments (1)
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! 👍