💅 Automatically Format PHP Code
Tags: php, laravel, lint, ci
Published: 2023-04-11 09:24:55

I love to have everything organised and to keep the code as clean as possible. And to do this by hand it's just really boring... And let's be honest it's also something from the past century because there are a lot of useful tools to beautifully help us keeping our beautiful code organised! 🙌

In this post, I'll show you how do I setup my PHP projects to be automatically formatted. 👀

## 1. Setup Formatter

### 1.1. Install the package [php-cs-fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer)

```bash
composer require friendsofphp/php-cs-fixer
```

### 1.2. Create a .php_cs file on the root of your project

```php
<?php

$finder = \PhpCsFixer\Finder::create()
    ->in(__DIR__)
    ->exclude(['bootstrap', 'storage', 'vendor'])
    ->name('*.php')
    ->ignoreDotFiles(true)
    ->ignoreVCS(true);

return PhpCsFixer\Config::create()
    ->setRules([
        '@PSR2' => true,
        'array_syntax' => ['syntax' => 'short'],
        'ordered_imports' => ['sortAlgorithm' => 'length'],
        'no_unused_imports' => true,
    ])
    ->setFinder($finder);
```

In this example, here's what will happen:

- bootstrap, storage and vendor directories will not be formatted.
- All `*.php` files will be considered.
- [PRS2](https://www.php-fig.org/psr/psr-2/) rules are the ones that are going to be used!
- Arrays like `array()` will be transformed to `[]`.
- Import statements will be ordered by their length to give that pyramid effect.
- Unused imports will be removed.

**Check the package documentation and change according your needs!**

### 1.3. Add a script to your composer.json file

```json
"scripts": {
	"format": "vendor/bin/php-cs-fixer fix"
}
```

### 1.4. Run it

```bash
composer format
```

Check the following basic example!

```php
<?php

namespace Package\Services;

// Unwanted space here!
use Package\Box;
use Illuminate\Support\Facades\Session as LaravelSession; // This should be the last!
use Package\Contracts\SomeInterface;

class SessionService implements SomeInterface
{
		// Unwanted space here!
    public function load(): Box
    {
        return LaravelSession::has(Box::class)
          ? LaravelSession::get(Box::class)
          : new Box();
    }
}
```

- Only 1 space after namespace.
- `LaravelSession` use line moved to the final import because of its length.
- Removed an empty line before `load` function.
- Added an empty line to the end of the file.

```php
<?php

namespace Package\Services;

use Package\Box;
use Package\Contracts\SomeInterface;
use Illuminate\Support\Facades\Session as LaravelSession;

class SessionService implements SomeInterface
{
    public function load(): Box
    {
        return LaravelSession::has(Box::class)
          ? LaravelSession::get(Box::class)
          : new Box();
    }
}

```

## 2. Make it run automatically

Now you can run it using composer. But that only means you can run the command... by hand!
Ideally would be to add this to your CI/CD pipeline alongside your tests! But most of the times, at least for me, I don't have a pipeline setup for really small projects like packages.

So I just use husky-php! This is a package for PHP to work with git hooks just like NPM's husky.

### 2.1. Install [husky-php](https://github.com/joaorbrandao/husky-php)

```bash
composer require --dev ccinn/composer-husky-plugin ccinn/husky-php
```

### 2.2. Add the hooks to composer.json

Check the package's documentation if you want to use other hooks!
Normally I just use `pre-commit` for formatting and `pre-push` for testing.

```json
{
  "hooks": {
    "pre-commit": "composer format",
  }
}
```

Now when you commit your code, `composer format` will run automatically! 🚀

I really hope that this is as useful for you as it was for me! 👋