Laravel Pint
Com mantenir un estil de codi consistent amb Laravel Pint: presets, regles personalitzades, integració amb CI/CD i editors.
Què és Laravel Pint?#
En qualsevol projecte de programació, l'estil del codi és un tema que genera debat. Tabuladors o espais? Claus a la mateixa línia o a la següent? Imports ordenats alfabèticament o per tipus? Cadascú té les seves preferències, i quan un equip de desenvolupadors treballa sobre el mateix codebase sense un estàndard comú, el resultat és un codi inconsistent que és més difícil de llegir, revisar i mantenir. Un fitxer utilitza un estil, el fitxer del costat en fa servir un altre, i els pull requests es contaminen amb canvis d'estil que no aporten res funcional.
Laravel Pint resol aquest problema de manera elegant i definitiva. Pint és un fixador d'estil de codi PHP basat en PHP-CS-Fixer que ve preinstal·lat amb cada projecte Laravel modern. Executar Pint reformatea automàticament tot el codi del projecte seguint un conjunt de regles predefinides. No cal debatre sobre estil: Pint decideix per tu, l'equip adopta l'estàndard i tothom es concentra en el que realment importa: la lògica del codi.
Per què l'estil consistent importa#
Un estil de codi consistent no és una qüestió estètica: és una qüestió de productivitat. Quan tot el codi segueix el mateix estil, els desenvolupadors llegeixen el codi més ràpidament perquè no han d'adaptar-se a convencions diferents en cada fitxer. Les revisions de codi (code reviews) són més eficients perquè els revisors es poden centrar en la lògica i l'arquitectura, no en detalls d'estil. I els diffs de Git són nets: cada canvi al diff representa un canvi real, no un reformatejat.
A més, un estil consistent redueix la fricció en equips nous. Quan un desenvolupador s'incorpora al projecte, no ha d'aprendre les convencions de l'equip: només ha d'executar Pint i el codi es formateja automàticament. Això és especialment valuós en projectes open source o en equips distribuïts on la comunicació sobre estàndards de codi és més difícil.
Preinstal·lat amb Laravel#
Una de les avantatges de Pint és que ja ve inclòs en tots els projectes Laravel nous. No cal instal·lar res: el binari ja està a vendor/bin/pint des del primer moment. Si per algun motiu no el tens (per exemple, en un projecte antic), pots instal·lar-lo amb Composer:
composer require laravel/pint --devEl flag --dev és important perquè Pint és una eina de desenvolupament: no ha d'estar a producció. El binari s'instal·la a vendor/bin/pint i ja és executable sense cap configuració addicional.
Ús bàsic#
La manera més senzilla d'usar Pint és executar-lo sense cap argument. Això analitza i corregeix automàticament tots els fitxers PHP del projecte:
./vendor/bin/pintPint mostrarà una llista dels fitxers que ha modificat i quines regles ha aplicat a cadascun. Per defecte, utilitza el preset laravel, que és l'estil oficial de Laravel.
Mode test (sense modificar fitxers)#
Si vols veure quins fitxers es modificarien sense aplicar els canvis, utilitza el flag --test. Això és útil per a CI/CD, on vols que el pipeline falli si hi ha fitxers que no segueixen l'estil, però no vols que el pipeline modifiqui els fitxers:
# Mostrar errors sense corregir-los
./vendor/bin/pint --testEl flag --test retorna un codi de sortida diferent de zero si hi ha fitxers que no segueixen l'estil. Això permet integrar Pint en pipelines de CI/CD com a comprovació obligatòria.
Només fitxers modificats#
En projectes grans, executar Pint sobre tot el codebase pot trigar uns segons. Si estàs treballant en una branca i només vols formatejar els fitxers que has modificat, utilitza el flag --dirty:
# Només els fitxers modificats (segons Git)
./vendor/bin/pint --dirtyEl flag --dirty utilitza git status per determinar quins fitxers han canviat respecte al darrer commit i només els processa. Això és molt més ràpid i és ideal per a hooks de pre-commit.
Fitxers o directoris específics#
Pots especificar fitxers o directoris concrets per processar:
# Un fitxer específic
./vendor/bin/pint app/Models/User.php
# Un directori sencer
./vendor/bin/pint app/Http/Controllers
# Múltiples rutes
./vendor/bin/pint app/Models app/ServicesSortida detallada#
Per veure exactament quines regles s'han aplicat a cada fitxer, utilitza el flag -v (verbose):
./vendor/bin/pint -vAixò mostra cada fitxer processat amb la llista de regles que s'hi han aplicat. Útil per entendre exactament què fa Pint al teu codi.
Presets en detall#
Pint inclou diversos presets, cadascun amb un conjunt de regles diferent. Un preset és un conjunt de regles preconfigurades que defineixen l'estil de codi complet: espaiat, claus, imports, tipus, declaracions i molt més.
Preset laravel (per defecte)#
El preset laravel és l'estil oficial del framework Laravel. Segueix les convencions que fa servir el propi codi font de Laravel i els seus paquets oficials. Algunes de les seves característiques principals:
- Claus d'obertura a la mateixa línia per a estructures de control (
if,for,while) - Claus d'obertura a la línia següent per a classes i mètodes
- Imports ordenats alfabèticament
- Espais al voltant dels operadors
- Línies en blanc abans de
return - Declaracions
useagrupades i ordenades - Tipus de retorn sense espai abans dels dos punts
// Exemple d'estil laravel
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class User extends Model
{
protected $fillable = [
'name',
'email',
'password',
];
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
}Preset psr12#
El preset psr12 segueix l'estàndard PSR-12, que és l'evolució de PSR-2 i l'estàndard de codi més adoptat en l'ecosistema PHP. PSR-12 és un estàndard de la PHP-FIG (Framework Interop Group) que defineix regles d'estil que la majoria de frameworks i llibreries PHP segueixen. Si el teu projecte necessita ser compatible amb estàndards de la comunitat PHP en general (no específics de Laravel), PSR-12 és l'elecció adequada.
Preset symfony#
El preset symfony segueix les convencions d'estil del framework Symfony. Si treballes en un projecte que combina components de Laravel i Symfony, o si el teu equip prové de l'ecosistema Symfony, aquest preset pot ser una bona opció per mantenir la familiaritat.
Preset per#
El preset per segueix l'estàndard PER (PHP Evolving Recommendation), l'evolució més recent dels estàndards PSR. PER és un estàndard viu que s'actualitza periòdicament per reflectir les pràctiques modernes de PHP. Si vols seguir les recomanacions més actuals de la comunitat PHP, PER és l'opció més avançada.
Per canviar el preset, utilitza el fitxer pint.json o el flag --preset:
# Via línia de comandes
./vendor/bin/pint --preset psr12
# O via configuració (recomanat)Configuració amb pint.json#
Per personalitzar el comportament de Pint, crea un fitxer pint.json a l'arrel del projecte. Aquest fitxer permet triar el preset base, afegir o sobreescriure regles específiques i excloure fitxers o directoris.
Configuració bàsica#
{
"preset": "laravel"
}Sobreescriure regles#
Pots afegir regles addicionals o modificar les del preset. Cada regla correspon a un "fixer" de PHP-CS-Fixer:
{
"preset": "laravel",
"rules": {
"simplified_null_return": true,
"blank_line_before_statement": {
"statements": ["return", "throw", "try"]
},
"ordered_imports": {
"sort_algorithm": "alpha",
"imports_order": ["const", "class", "function"]
},
"no_unused_imports": true,
"single_quote": true,
"trailing_comma_in_multiline": {
"elements": ["arrays", "arguments", "parameters"]
},
"concat_space": {
"spacing": "one"
}
}
}Deshabilitar regles#
Si una regla del preset no t'agrada, pots deshabilitar-la posant-la a false:
{
"preset": "laravel",
"rules": {
"simplified_null_return": false,
"new_with_parentheses": false
}
}Excloure fitxers i directoris#
De vegades hi ha fitxers que no vols que Pint toqui: fitxers generats automàticament, codi de tercers que no vols modificar o fitxers amb un estil intencionadament diferent:
{
"preset": "laravel",
"exclude": [
"vendor",
"node_modules",
"storage",
"bootstrap/cache",
"database/migrations"
],
"notName": [
"*.blade.php",
"_ide_helper.php"
],
"notPath": [
"tests/Stubs"
]
}Exemple complet de configuració#
Aquesta és una configuració completa que molts equips troben útil com a punt de partida:
{
"preset": "laravel",
"rules": {
"simplified_null_return": true,
"blank_line_before_statement": {
"statements": ["break", "continue", "return", "throw", "try"]
},
"ordered_imports": {
"sort_algorithm": "alpha",
"imports_order": ["const", "class", "function"]
},
"no_unused_imports": true,
"not_operator_with_successor_space": true,
"trailing_comma_in_multiline": {
"elements": ["arrays", "arguments", "parameters"]
},
"php_unit_method_casing": {
"case": "snake_case"
},
"concat_space": {
"spacing": "one"
},
"single_line_empty_body": true,
"declare_strict_types": true
},
"exclude": [
"vendor",
"node_modules"
]
}Regles comunes explicades#
Pint inclou centenars de regles disponibles (heretades de PHP-CS-Fixer), però algunes són especialment rellevants per a projectes Laravel.
no_unused_imports#
Elimina les declaracions use que no s'utilitzen al fitxer. Això és una de les regles més útils perquè els imports no utilitzats s'acumulen ràpidament quan es refactoritza codi:
// Abans
use App\Models\User;
use App\Models\Post; // No s'utilitza
use Illuminate\Http\Request;
class UserController
{
public function show(Request $request, User $user) {}
}
// Després (amb no_unused_imports)
use App\Models\User;
use Illuminate\Http\Request;
class UserController
{
public function show(Request $request, User $user) {}
}ordered_imports#
Ordena les declaracions use alfabèticament. Això elimina debats sobre l'ordre dels imports i fa que els diffs de Git siguin més predictibles:
// Abans
use Illuminate\Http\Request;
use App\Models\User;
use Carbon\Carbon;
use App\Events\UserCreated;
// Després (amb ordered_imports: alpha)
use App\Events\UserCreated;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Http\Request;trailing_comma_in_multiline#
Afegeix una coma final als elements multilínia (arrays, arguments de funcions, paràmetres). Això fa que els diffs de Git siguin més nets perquè afegir un element nou no modifica la línia anterior:
// Sense trailing comma
$data = [
'name' => 'Joan',
'email' => 'joan@example.com' // Afegir un camp aquí modifica aquesta línia
];
// Amb trailing comma
$data = [
'name' => 'Joan',
'email' => 'joan@example.com', // Afegir un camp nou no toca aquesta línia
];declare_strict_types#
Afegeix declare(strict_types=1) a tots els fitxers PHP. Això activa el mode estricte de tipus de PHP, cosa que fa que les conversions implícites de tipus llancin un error en lloc de fer una conversió silenciosa. És una pràctica recomanada per a codi robust:
<?php
declare(strict_types=1);
namespace App\Models;Activa declare_strict_types amb precaució en projectes existents. Si el codi existent depèn de conversions implícites de tipus (per exemple, passar un string on s'espera un enter), activar el mode estricte pot causar errors en temps d'execució. Aplica-ho progressivament i amb tests.
simplified_null_return#
Simplifica els return null explícits a return quan la funció no declara un tipus de retorn:
// Abans
public function find($id)
{
$user = User::find($id);
if (! $user) {
return null;
}
return $user;
}
// Després
public function find($id)
{
$user = User::find($id);
if (! $user) {
return;
}
return $user;
}blank_line_before_statement#
Afegeix una línia en blanc abans de determinades sentències per millorar la llegibilitat:
// Abans
$user = User::find($id);
$user->update($data);
return $user;
// Després (amb blank_line_before_statement: return)
$user = User::find($id);
$user->update($data);
return $user;Integració amb CI/CD#
Una de les utilitats més importants de Pint és integrar-lo en el pipeline de CI/CD perquè cap codi que no segueixi l'estil pugui arribar a la branca principal. Això garanteix que l'estil es manté consistent al llarg del temps, independentment de qui faci el commit.
GitHub Actions#
Crea un workflow de GitHub Actions que executi Pint en mode test per a cada pull request:
# .github/workflows/pint.yml
name: Code Style
on:
pull_request:
branches: [main, develop]
push:
branches: [main, develop]
jobs:
pint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
coverage: none
- name: Install Dependencies
run: composer install --no-interaction --prefer-dist
- name: Run Pint
run: ./vendor/bin/pint --testAmb aquest workflow, cada pull request que contingui codi que no segueixi l'estil fallarà la comprovació. El desenvolupador haurà d'executar ./vendor/bin/pint localment per corregir l'estil abans de tornar a pujar els canvis.
GitLab CI#
# .gitlab-ci.yml
code-style:
image: php:8.3-cli
stage: test
before_script:
- curl -sS https://getcomposer.org/installer | php
- php composer.phar install --no-interaction
script:
- ./vendor/bin/pint --test
only:
- merge_requestsIntegració amb editors#
L'experiència ideal és que l'editor formategi el codi automàticament cada vegada que guardes un fitxer. Això elimina completament la necessitat de pensar en estil: escrius el codi com vulguis i l'editor l'adapta a l'estàndard automàticament.
VS Code#
Per integrar Pint amb VS Code, necessites l'extensió "Laravel Pint" que permet configurar el format on save:
// .vscode/settings.json
{
"editor.formatOnSave": true,
"[php]": {
"editor.defaultFormatter": "open-southeners.laravel-pint",
"editor.formatOnSave": true
},
"laravel-pint.enable": true
}Inclou el fitxer .vscode/settings.json al repositori perquè tots els membres de l'equip tinguin la mateixa configuració de l'editor.
PHPStorm#
PHPStorm té suport integrat per a eines de format de codi extern. Per configurar Pint:
- Ves a
Settings > PHP > Quality Tools > External Formatters - Activa "PHP CS Fixer" (Pint és compatible perquè està basat en PHP-CS-Fixer)
- Configura el camí al binari:
./vendor/bin/pint - Activa "Run on Reformat Code" i "Run on Save"
Alternativament, pots configurar Pint com a File Watcher:
- Ves a
Settings > Tools > File Watchers - Crea un nou watcher de tipus "Custom"
- Configura el programa:
$ProjectFileDir$/vendor/bin/pint - Arguments:
$FilePath$ - Desactiva "Auto-save edited files to trigger the watcher" per evitar execucions innecessàries
Pre-commit hooks#
Els hooks de pre-commit executen Pint automàticament abans de cada commit. Si Pint detecta que hi ha fitxers que no segueixen l'estil, el commit es bloqueja fins que es corregeixi. Això actua com a última línia de defensa: encara que el desenvolupador s'oblidi d'executar Pint manualment, el hook ho farà per ell.
Hook natiu de Git#
La manera més senzilla és crear un hook de pre-commit directament amb Git:
#!/bin/sh
# .git/hooks/pre-commit
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep "\.php$")
if [ -z "$STAGED_FILES" ]; then
exit 0
fi
echo "Executant Laravel Pint sobre els fitxers staged..."
./vendor/bin/pint --dirty --test
if [ $? -ne 0 ]; then
echo ""
echo "Pint ha detectat problemes d'estil. Executa './vendor/bin/pint --dirty' per corregir-los."
exit 1
fi
exit 0chmod +x .git/hooks/pre-commitAmb Husky (per a projectes amb npm)#
Si el teu projecte Laravel utilitza npm (per exemple, amb Vite), pots fer servir Husky per gestionar els hooks de Git de manera més elegant i compartible:
npm install --save-dev husky
npx husky initCrea el hook de pre-commit:
# .husky/pre-commit
./vendor/bin/pint --dirty --testL'avantatge de Husky sobre els hooks natius de Git és que els hooks es defineixen al repositori i s'instal·len automàticament quan algú fa npm install. Amb els hooks natius, cada desenvolupador ha de configurar-los manualment.
Si combinees pre-commit hooks amb CI/CD, tens dues capes de protecció: el hook evita que el desenvolupador faci commit de codi mal formatejat, i el CI/CD evita que codi mal formatejat arribi a la branca principal (per si algú desactiva el hook).
Pint vs PHP-CS-Fixer#
Pint està construït sobre PHP-CS-Fixer, la qual cosa genera la pregunta: per què existeix Pint si PHP-CS-Fixer ja existeix? La resposta és que Pint simplifica l'experiència per a desenvolupadors Laravel.
PHP-CS-Fixer és una eina molt potent però també molt configurable. Té centenars de regles, múltiples formats de configuració i una corba d'aprenentatge considerable. Per a un nou desenvolupador Laravel, configurar PHP-CS-Fixer amb l'estil de Laravel requereix recerca, proves i temps.
Pint és PHP-CS-Fixer amb una capa de simplicitat al damunt. El preset laravel és la configuració per defecte, la instal·lació és automàtica i l'ús és immediat. Si necessites personalitzar alguna regla, pots fer-ho amb un fitxer JSON senzill (pint.json) en lloc del format PHP de PHP-CS-Fixer (.php-cs-fixer.php).
En resum: si treballes amb Laravel, utilitza Pint. Si treballes amb un projecte PHP genèric que no utilitza Laravel, utilitza PHP-CS-Fixer directament. Les regles són les mateixes; la diferència és la conveniència.
| Característica | Laravel Pint | PHP-CS-Fixer |
|---|---|---|
| Instal·lació | Preinstal·lat amb Laravel | Manual (composer require) |
| Configuració | pint.json (JSON senzill) | .php-cs-fixer.php (PHP) |
| Presets Laravel | Per defecte | Configuració manual |
| Corba d'aprenentatge | Mínima | Moderada |
| Regles disponibles | Totes les de PHP-CS-Fixer | Totes |
| Projectes no-Laravel | Possible, però no ideal | Dissenyat per a qualsevol projecte |
| Zero-config | Sí | No |
Executar Pint en projectes existents#
Si tens un projecte existent que no ha fet servir cap eina de format de codi, el primer cop que executis Pint probablement modificarà centenars de fitxers. Això pot ser intimidant, però hi ha estratègies per gestionar-ho:
La primera opció és fer un "big bang": executa Pint sobre tot el projecte en un sol commit dedicat. Això crea un diff enorme, però és un sol commit que clarament diu "Aplicar estil de codi amb Laravel Pint". Les futures revisions de codi seran netes perquè tot el codi ja seguirà el mateix estil. Assegura't d'executar els tests després per verificar que Pint no ha trencat res (no hauria, perquè només canvia l'estil, no la lògica).
# Executar Pint sobre tot el projecte
./vendor/bin/pint
# Verificar que tot funciona
php artisan test
# Commit dedicat
git add -A
git commit -m "style: Apply Laravel Pint code formatting"La segona opció és fer-ho progressivament: configura el pre-commit hook perquè apliqui Pint només als fitxers modificats (--dirty). Amb el temps, a mesura que l'equip modifica fitxers, cada fitxer tocat es formateja automàticament. Després d'uns mesos, la majoria del codebase seguirà l'estil correcte.
Si optes pel "big bang", pots fer servir git blame --ignore-rev per dir a Git que ignori el commit de format a l'hora de mostrar l'últim autor de cada línia. Crea un fitxer .git-blame-ignore-revs amb el hash del commit i configura Git per usar-lo: git config blame.ignoreRevsFile .git-blame-ignore-revs.