How to setup Git commit hooks for PHP
Tags: git, php, hook, ci
Published: 2020-08-10 15:20:48

---
title: How to setup Git commit hooks for PHP
published: true
description: Supercharge your Git Game with this simple hook
tags: ['git','php','hook','ci']
//cover_image: https://direct_url_to_image.jpg
---

This very simple script will run these checks each time you commit:

- **PHP Internal Linter** to check your code for syntax errors
- **PHP Code Sniffer** to check for coding standard (PSR-2)
- **PHPStan** to analyse the code and find bugs

Overall it takes a few seconds and it analyses **only** the staged files - those in green when you do a `git status`.

If a single check fails the error message is displayed and the commit is aborted.

Example:

```
[1/3] php lint            OK!
[2/3] code sniffer        OK!
[3/3] phpstan             NOK!

 1/1 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%

 ------ --------------------------------------------------------------------- 
  Line   CanSendInvitation.php                                                
 ------ --------------------------------------------------------------------- 
  14     Parameter $lol of method App\Rules\CanSendInvitation::__construct()  
         has invalid typehint type App\Rules\Noob.                            
 ------ --------------------------------------------------------------------- 

 [ERROR] Found 1 error                                                          
```

## Step 1: requirements

You're going to need some packages to validate your code so go ahead and install:

```BASH
composer install --dev phpstan/phpstan
composer install --dev squizlabs/php_codesniffer
```

## Step 2: create the hook

In `.git/hooks/pre-commit` write:

```BASH
#!/usr/bin/env bash

# get bash colors and styles here: 
# http://misc.flogisoft.com/bash/tip_colors_and_formatting
C_RESET='\e[0m'
C_RED='\e[31m'
C_GREEN='\e[32m'
C_YELLOW='\e[33m'

function __run() #(step, name, cmd)
{
    local color output exitcode

    printf "${C_YELLOW}[%s]${C_RESET} %-20s" "$1" "$2"
    output=$(eval "$3" 2>&1)
    exitcode=$?

    if [[ 0 == $exitcode || 130 == $exitcode ]]; then
        echo -e "${C_GREEN}OK!${C_RESET}"
    else
        echo -e "${C_RED}NOK!${C_RESET}\n\n$output"
        exit 1
    fi
}

modified="git diff --diff-filter=M --name-only --cached  | grep \".php$\""
ignore="resources/lang,resources/views,bootstrap/helpers,database/migrations,bin"
phpcs="vendor/bin/phpcs --report=code --colors --report-width=80 --standard=PSR2 --ignore=${ignore}"

__run "1/3" "php lint" "${modified} | xargs -r php -l"
__run "2/3" "code sniffer" "${modified} | xargs -r ${phpcs}"
__run "3/3" "phpstan" "${modified} | xargs -r vendor/bin/phpstan analyse"
```

The line 
```BASH
ignore="resources/lang,resources/views,bootstrap/helpers,database/migrations,bin"
``` 

is project specific. It's the comma separated list of paths to ignore in the PHP Code Sniffer analysis. Typically, you add the paths for which the PSR-2 makes no sense, like configuration or translation files.

You may change it to whatever you want.

---

My team has been using and refining this script for years and it has saved us countless hours in refactoring. The sooner you detect errors the better.

Our real script includes more tests that are specific to our app like unit & behavioral test to ensure you broke nothing. I'm sure with a little imagination you are capable to adapt the script to your project. 

I suggest you play around with it and share what you find out in the comments.

---

A usual don't forget to like and comment, that keeps me motivated to write more content for you!

Happy coding!