Laravel Pint - Code Formatting Tool
Automatically format PHP code to ensure consistent team code style
Table of Contents
- Introduction
- Installation and Configuration
- Configuration File
- Usage
- CI Integration
- Common Issues
- Best Practices
Introduction
What is Laravel Pint?
Laravel Pint is a zero-configuration code formatter based on PHP-CS-Fixer, designed specifically for PHP projects. It supports PSR-12 and PER Coding Style standards.
Key Features:
- Zero configuration out of the box
- Supports PSR-12 and PER-CS
- Fast formatting
- Friendly output interface
- Git integration support
Installation and Configuration
Installation
# Install as dev dependency
composer require --dev laravel/pint
# Verify installation
./vendor/bin/pint --versionConfigure Composer Scripts
Add shortcut commands in composer.json:
{
"scripts": {
"fmt": "pint",
"fmt:test": "pint --test",
"fmt:dirty": "pint --dirty"
},
"scripts-descriptions": {
"fmt": "Format all PHP files",
"fmt:test": "Check code style without modifying files",
"fmt:dirty": "Format only Git uncommitted files"
}
}Usage:
composer fmt # Format all files
composer fmt:test # Check only, no modifications
composer fmt:dirty # Format only uncommitted filesConfiguration File
pint.json
Create pint.json in the project root:
PSR-12 Configuration
{
"preset": "psr12",
"exclude": [
"vendor",
"storage",
"runtime",
"node_modules"
],
"rules": {
"blank_line_after_opening_tag": true,
"blank_line_between_import_groups": true,
"class_attributes_separation": {
"elements": {
"method": "one",
"property": "one",
"trait_import": "none"
}
},
"method_argument_space": {
"on_multiline": "ensure_fully_multiline"
},
"no_unused_imports": true,
"ordered_imports": {
"sort_algorithm": "alpha"
},
"single_import_per_statement": true,
"trailing_comma_in_multiline": {
"elements": ["arrays", "arguments", "parameters"]
}
}
}PER Coding Style Configuration
{
"preset": "per",
"exclude": [
"vendor",
"storage",
"runtime",
"node_modules"
],
"rules": {
"blank_line_after_opening_tag": true,
"blank_line_between_import_groups": true,
"class_attributes_separation": {
"elements": {
"method": "one",
"property": "one",
"trait_import": "none",
"const": "one",
"case": "none"
}
},
"concat_space": {
"spacing": "one"
},
"declare_strict_types": true,
"final_class": false,
"final_internal_class": false,
"global_namespace_import": {
"import_classes": true,
"import_constants": true,
"import_functions": true
},
"method_argument_space": {
"on_multiline": "ensure_fully_multiline",
"keep_multiple_spaces_after_comma": false
},
"no_unused_imports": true,
"nullable_type_declaration": {
"syntax": "question_mark"
},
"ordered_imports": {
"sort_algorithm": "alpha",
"imports_order": ["class", "function", "const"]
},
"phpdoc_align": {
"align": "left"
},
"phpdoc_separation": true,
"phpdoc_summary": false,
"single_import_per_statement": true,
"trailing_comma_in_multiline": {
"elements": ["arrays", "arguments", "parameters", "match"]
},
"type_declaration_spaces": {
"elements": ["function", "property"]
},
"types_spaces": {
"space": "none"
}
}
}Configuration Explanation
| Rule | Description |
|---|---|
preset | Preset rule set (psr12/per/laravel) |
exclude | Excluded directories |
declare_strict_types | Enforce strict_types declaration |
no_unused_imports | Remove unused imports |
ordered_imports | Sort imports alphabetically |
trailing_comma_in_multiline | Trailing comma in multiline |
Usage
Basic Commands
# Format all files
./vendor/bin/pint
# Format specific directory
./vendor/bin/pint app/domain
./vendor/bin/pint app/service app/controller
# Format specific file
./vendor/bin/pint app/domain/order/entity/Order.php
# Check only, don't modify files (for CI)
./vendor/bin/pint --test
# Format only Git uncommitted files
./vendor/bin/pint --dirty
# Show verbose output
./vendor/bin/pint -v
# Show all modified files
./vendor/bin/pint -vv
# Show all modification details
./vendor/bin/pint -vvvUse Cases
Case 1: Auto-format during development
# Run after saving file
composer fmt
# Or use Git hooks (see below)Case 2: Pre-commit check
# Format only modified files
composer fmt:dirty
# Check compliance
composer fmt:testCase 3: CI validation
# Run in CI, fail if non-compliant
./vendor/bin/pint --testCI Integration
GitHub Actions
Add to .github/workflows/code-quality.yml:
name: Code Quality
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
pint:
name: Laravel Pint
runs-on: ubuntu-latest
steps:
- name: Checkout code
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 --prefer-dist --no-progress --no-interaction
- name: Run Pint
run: ./vendor/bin/pint --test -vGitLab CI
Add to .gitlab-ci.yml:
pint:
stage: test
image: php:8.3-cli
before_script:
- curl -sS https://getcomposer.org/installer | php
- php composer.phar install --prefer-dist --no-progress
script:
- ./vendor/bin/pint --test -v
only:
- merge_requests
- main
- developGit Hooks (Pre-commit)
Create .git/hooks/pre-commit:
#!/bin/bash
# Get all PHP files to be committed
FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.php$')
if [ -z "$FILES" ]; then
exit 0
fi
# Run Pint
./vendor/bin/pint $FILES
# Re-add formatted files
git add $FILES
exit 0Grant execute permission:
chmod +x .git/hooks/pre-commitRecommend using Husky or GrumPHP to manage Git Hooks.
Common Issues
Q1: Pint modified files I didn't want changed
Problem: Pint formatted vendor or third-party code.
Solution: Add exclude in pint.json:
{
"exclude": [
"vendor",
"storage",
"runtime",
"node_modules",
"public/static"
]
}Q2: How to ignore specific files?
Method 1: Use .gitignore style exclude:
{
"exclude": [
"app/legacy/*",
"tests/fixtures/*"
]
}Method 2: Add comments in file (not recommended):
<?php
// @formatter:off
class LegacyCode
{
// Keep original format
}
// @formatter:onQ3: Pint and PHP-CS-Fixer conflict
Problem: Project uses both Pint and PHP-CS-Fixer.
Solution:
- Recommended: Use only Pint (simpler)
- If PHP-CS-Fixer is required, remove Pint
- Don't use both simultaneously
Q4: How to integrate with IDE?
PHPStorm
- Install "Laravel Pint" plugin
- Settings -> Tools -> Laravel Pint
- Configure Pint path:
vendor/bin/pint - Enable "Run on save"
VS Code
- Install "Laravel Pint" extension
- Configure in
settings.json:
{
"laravel-pint.enable": true,
"laravel-pint.runOnSave": true,
"laravel-pint.configPath": "pint.json"
}Q5: Pint runs slowly
Optimization:
# Format only modified files
./vendor/bin/pint --dirty
# Use parallel processing (requires PHP 8.1+)
./vendor/bin/pint --parallel
# Specify specific directories
./vendor/bin/pint app/domain app/serviceBest Practices
Recommended
Configure Pint early in the project
bashcomposer require --dev laravel/pint # Create pint.json immediatelyUse PER Coding Style preset
json{ "preset": "per" }Configure Git Hooks
- Auto-format before commit
- Avoid committing non-compliant code
Validate in CI
bash./vendor/bin/pint --testUnified team configuration
- Commit
pint.jsonto version control - All members use the same configuration
- Commit
Use Composer Scripts
bashcomposer fmt # Easy to remember composer fmt:test # For CI
Avoid
Don't manually format code
- Manually adjusting indentation and spaces
- Let Pint handle it automatically
Don't ignore Pint's modifications
- Not committing after formatting
- Commit immediately after formatting
Don't install Pint in production
bash# Wrong composer require laravel/pint # Correct composer require --dev laravel/pintDon't over-customize rules
- Modifying many default rules
- Use presets, only adjust necessary rules
Don't format third-party code
json{ "exclude": ["vendor", "storage"] }
Workflow Examples
Daily Development Flow
# 1. Write code
vim app/service/order/CreateOrderService.php
# 2. Format after saving
composer fmt
# 3. View changes
git diff
# 4. Commit code
git add .
git commit -m "feat: add CreateOrderService"Code Review Flow
# 1. Create branch
git checkout -b feature/new-service
# 2. Develop feature
# ... write code ...
# 3. Format before commit
composer fmt:dirty
# 4. Check compliance
composer fmt:test
# 5. Commit and push
git add .
git commit -m "feat: implement new service"
git push origin feature/new-service
# 6. CI auto-validates code styleIntegration with Other Tools
Pint + PHPStan
# Format first, then static analysis
composer fmt && composer stanIn composer.json:
{
"scripts": {
"check": [
"@fmt:test",
"@stan"
]
}
}Pint + Pest
# Run tests after formatting
composer fmt && composer testComplete Quality Check
{
"scripts": {
"quality": [
"@fmt:test",
"@stan",
"@test"
]
}
}Run:
composer quality