Why I Revisited the Formatting Setup
This was not a situation where I suddenly needed a new formatter. Laravel Pint had already been in require-dev for quite a while, but I had never actually used it.
The real formatting workflow was built around friendsofphp/php-cs-fixer: a separate .php-cs-fixer.dist.php, a custom fixers package, and a PHP-CS-Fixer check in CI.
While reviewing the project's tooling, I noticed the mismatch: Pint was already a dependency, but all actual formatting was done by another tool. That was when I decided to check whether PHP-CS-Fixer was still giving me anything I could not reasonably cover with Pint before removing the old setup.
I Started by Checking What PHP-CS-Fixer Was Actually Doing
<?php $finder = (new PhpCsFixer\Finder()) ->in(__DIR__) ->exclude(['bootstrap', 'storage', 'public', 'node_modules', 'vendor']); return (new PhpCsFixer\Config()) ->registerCustomFixers(new PhpCsFixerCustomFixers\Fixers()) ->setRules([ '@PSR12' => true, '@PHP81Migration' => true, PhpCsFixerCustomFixers\Fixer\ConstructorEmptyBracesFixer::name() => true, PhpCsFixerCustomFixers\Fixer\NoUselessCommentFixer::name() => true, PhpCsFixerCustomFixers\Fixer\PhpdocNoIncorrectVarAnnotationFixer::name() => true, 'binary_operator_spaces' => [ 'default' => 'single_space', 'operators' => [ '=' => 'single_space', '=>' => 'single_space', ], ], 'not_operator_with_successor_space' => true, 'cast_spaces' => true, 'array_syntax' => ['syntax' => 'short'], 'phpdoc_scalar' => true, 'phpdoc_align' => [ 'align' => 'left', ], ]) ->setFinder($finder);I did not want to delete this config and simply assume Pint would do roughly the same thing. I reviewed the rules first and compared them with Pint's Laravel preset.
Regular style rules such as spacing, short array syntax, casts, and PHPDoc formatting did not need to be copied manually when the required behavior was already covered by Pint.
Some rules were different. @PHP81Migration, for example, is more than formatting: it is a migration ruleset that can transform code.
I also chose not to carry over custom fixers that modify or remove comments and PHPDoc content. I wanted a clearer boundary: the formatter should format code, while semantic code or documentation cleanup should remain a separate concern.
What existed in PHP-CS-Fixer | What I decided |
|---|---|
Regular style rules | Do not duplicate them when Pint already covers the required style |
@PHP81Migration | Do not move it into formatter configuration |
Constructor formatting | Keep Pint's standard formatting |
Comment/PHPDoc custom fixers | Do not preserve them as formatting rules |
Separate Finder scope | Do not reproduce it mechanically; use Pint's normal project scope |
.php-cs-fixer.dist.php | Remove it after the audit |
I also did not reproduce the old Finder scope one-to-one. PHP-CS-Fixer excluded `bootstrap`, for example, while during the migration I intentionally ran Pint across its normal project scope and brought the PHP files in `bootstrap` to the same style as well.
After the Audit, I Decided to Keep Only Laravel Pint
After comparing the setups, I no longer had a good reason to maintain a separate PHP-CS-Fixer workflow.
Pint was already a project dependency, the Laravel preset covered the baseline code style I needed, and the specific rules in the old formatter either did not require separate configuration anymore or did not really belong to formatting.
So instead of maintaining two tools, I decided to make Pint the single formatter for the PHP codebase.
The Pint Configuration Ended Up Being Very Small
{ "preset": "laravel"}At first, this `pint.json` looked almost suspiciously small compared with the old PHP-CS-Fixer config. But that was exactly what I wanted: start with the Laravel preset and only add overrides when the project has a real reason for them.
Then I Removed PHP-CS-Fixer from the Project
PHP-CS-Fixer — actual formatter
.php-cs-fixer.dist.php
php-cs-fixer-custom-fixers
PHP-CS-Fixer check in CI
Laravel Pint in require-dev, but unused
Laravel Pint — the only formatter
pint.json
composer format
composer format:check
Pint check in CI
PHP-CS-Fixer dependencies and config removed
I removed the direct friendsofphp/php-cs-fixer and kubawerlos/php-cs-fixer-custom-fixers dependencies from composer.json. Composer also removed the transitive packages that had only been required by that tooling.
Then I deleted .php-cs-fixer.dist.php, the old cache file, and its entries in .gitignore.
I also updated the README, deployment documentation, and GitLab CI. I did not want a half-finished migration where Pint was used locally while old PHP-CS-Fixer commands were still documented or executed in the pipeline.
CI matters to me here as an extension of the local workflow: the same check should run automatically in the pipeline. I wrote separately about how I see that CI/CD flow and how its presentation differed for me in Bitbucket CI Bot and GitLab Pipeline.
{ "scripts": { "format": "pint", "format:check": "pint --test" }}I intentionally exposed the commands through Composer scripts so I would not need to remember the exact binary path and could use the same interface locally and in CI.
pint: extends: .php_job stage: quality script: - composer format:checkMy First Real Pint Run Found 244 Style Issues
Until this point, Pint had only existed in the project as a dependency. This was the first time I actually used it as the formatter, and I started with a check that did not modify any files.
composer format:check
Pint checked 801 PHP files and found 244 style issues. That gave me a clear picture of the difference between the style that had been maintained by PHP-CS-Fixer and the baseline applied by Laravel Pint.
I Decided to Bring the Whole PHP Codebase to One Baseline
composer format
Because this was a project-wide formatting pass, the diff was large: 252 files changed in total.
That was expected. In addition to removing the old tooling and updating configuration, Pint reformatted PHP code across app, database, routes, config, bootstrap, and tests.
That is why I kept this work in a separate task. A large formatting diff is much easier to review when it is not mixed with new functionality or business logic changes.
I Verified More Than Just Pint Afterwards
Because the formatter touched a large number of PHP files, I wanted to make sure the migration remained a formatting-only change.
After the formatting pass, composer format:check was clean, PHPStan reported no errors, and the Unit, Integration, and Feature test suites also completed successfully.
Only after those checks did I consider the migration finished.
Now I Have One Clear Formatting Workflow
composer format composer format:checkI use `composer format` when I want Pint to update the code automatically. `composer format:check` does not modify anything and only validates the current state, so that is the command I use in CI.
What I Took Away from This Cleanup
A dependency being present in composer.json does not mean the project is actually using it.
Audit the old tooling configuration before removing it.
Do not automatically move every old rule into the new formatter.
Migration rules and comment cleanup do not necessarily belong in a formatter.
One formatter, one local workflow, and one CI check are much easier to maintain.
Keep project-wide formatting changes separate from functional changes.
In the end, I did not introduce Pint from scratch. It was already in the project; I simply had never used it. I audited the existing PHP-CS-Fixer configuration, kept only what still made sense, removed the redundant tooling, and made Pint the single formatting mechanism for the PHP codebase.



