Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Debug Statements Fixers Laravel Package

drew/debug-statements-fixers

Laravel Pint fixers that automatically detect and remove leftover debug statements such as dd(), dump(), var_dump(), print_r(), and ray() from your PHP codebase. Easily keep commits and production code clean, consistent, and free of accidental debugging calls.

View on GitHub
Deep Wiki
Context7

Getting

composer require --dev drew/debug-statements-fixers friendsofphp/php-cs-fixer

The package is a PHP-CS-Fixer plugin, not a standalone tool — it ships fixer classes (Dump, VarDump, PrintR, DebugPrintR, etc.) that you register into a PHP-CS-Fixer config. So the first thing to check is composer.json inside vendor/drew/debug-statements-fixers: it was released in 2018, so expect a friendsofphp/php-cs-fixer: ^2.x constraint. Confirm which major version Composer actually resolved before going further:

composer show friendsofphp/php-cs-fixer drew/debug-statements-fixers
ls vendor/drew/debug-statements-fixers/src

Where to look first: the src/ directory listing gives you the class names, and each class's getName() gives you the rule name to put in setRules(). You can also discover them from the CLI:

vendor/bin/php-cs-fixer describe Akovalyov/dump   # exact name from getName()
vendor/bin/php-cs-fixer list-files --rules        # or inspect the registered set

A minimal .php-cs-fixer.php (.php_cs on the 2.x line):

<?php

$finder = PhpCsFixer\Finder::create()
    ->in([__DIR__.'/app', __DIR__.'/routes', __DIR__.'/database', __DIR__.'/tests'])
    ->exclude(['storage', 'bootstrap/cache']);

return (new PhpCsFixer\Config())
    ->registerCustomFixers([
        new Akovalyov\DebugStatementsFixers\Dump(),
        new Akovalyov\DebugStatementsFixers\VarDump(),
        new Akovalyov\DebugStatementsFixers\PrintR(),
    ])
    ->setRiskyAllowed(true)
    ->setRules([
        'Akovalyov/dump'    => true,
        'Akovalyov/var_dump' => true,
        'Akovalyov/print_r'  => true,
        // clean up the blank lines the removals leave behind
        'no_extra_blank_lines' => true,
    ])
    ->setFinder($finder);

First use case — the one that pays for itself: a CI/pre-push guard.

vendor/bin/php-cs-fixer fix --dry-run --diff --using-cache=no app/ routes/

Exit code 8 means "would have changed files" → fail the build with the diff in the log. This catches the dd($user) someone left in a controller at 23:40 before it reaches staging.

Implementation Patterns

Dedicated guard config, separate from formatting. Keep two configs: .php-cs-fixer.php for full style (if you use it at all) and .php-cs-fixer.debug.php containing only the debug fixers. The guard config is fast, has near-zero diff noise, and won't reflow the codebase when you only wanted to catch dump().

vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.debug.php --dry-run --diff

Local autofix vs. CI dry-run. Same config, different flags — developers run fix, CI runs fix --dry-run:

{
  "scripts": {
    "lint:debug": "php-cs-fixer fix --config=.php-cs-fixer.debug.php --dry-run --diff --using-cache=no",
    "fix:debug": "php-cs-fixer fix --config=.php-cs-fixer.debug.php --diff"
  }
}

Check only what changed. On a large repo, scanning everything is slow and surfaces legacy debt you can't fix today. In CI, feed the finder the diff:

FILES=$(git diff --name-only --diff-filter=ACMR origin/main... | grep -E '\.php$')
[ -n "$FILES" ] && vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.debug.php \
  --path-mode=intersection --dry-run --diff $FILES

Coexist with Pint. Laravel Pint wraps PHP-CS-Fixer internally and does not expose registerCustomFixers, so this package cannot be plugged into pint.json. Run them as two independent steps (Pint for style, this for the debug guard) — don't try to merge them.

Layer with grep for what fixers can't see. PHP-CS-Fixer only parses .php files. Blade and config-free spots need a separate check:

git grep -nE '\b(dd|dump|ray|var_dump|print_r)\s*\(' -- '*.blade.php' '*.php' && exit 1 || true

This is also your safety net for Log::debug, logger()->debug() and any custom debug helpers the package doesn't know about.

Pre-commit hook. Wire fix:debug into CaptainHook / Husky / a plain .git/hooks/pre-commit so the statement never lands in the index at all — cheaper than a CI round trip.

Editor integration. Any PHP-CS-Fixer plugin for PhpStorm/VS Code can point at .php-cs-fixer.debug.php with "fix on save", giving you automatic removal during normal editing.

Gotchas and Tips

  • The dependency conflict is the main risk. Laravel Pint 1.x requires friendsofphp/php-cs-fixer: ^3.0; a 2018 package almost certainly requires ^2.x. Composer will hard-fail on composer require --dev. Options: install the tool in a separate tools/composer.json (or a global Composer bin dir), run it from a phar, or — the pragmatic answer — vendor the fixer classes. They're a handful of small classes; copying them into tools/fixers/ and adapting the FixerInterface signatures to v3 removes a dead dependency entirely. With 22 stars, 0 dependents and a last release in 2018, treat it as reference source, not a maintained dependency.
  • Deletion is only safe for statement-position calls. The fixer removes the statement. dd($x) on its own line → fine. return dd($x);, $x = dd($x);, foo(dd($x)), $x = $y ?: dump($z); → you can get a syntax error or a silently changed return value. Always review --dry-run --diff output on unfamiliar code, and run the test suite after any autofix commit.
  • Nested/multi-line dumps may be partially handled. dd(tap($user, fn ($u) => var_dump($u))); may only lose the outer (or inner) call. Read the diff; don't --dry-run-and-merge blind.
  • Risky fixers. These change runtime behaviour, so they may be flagged risky — ->setRiskyAllowed(true) in the config, and understand you're opting into behavioural edits.
  • Blank-line residue. Removing a statement often leaves a double blank line or a dangling blank line after {. Pair with no_extra_blank_lines and blank_line_before_statement in the same config, otherwise the guard produces style churn that reviewers start ignoring.
  • The tool never "fails" — it rewrites. Without --dry-run, fix exits 0 after silently deleting code. CI must use --dry-run; the human workflow uses plain fix. Mixing these up is how a guard becomes a no-op.
  • Cache surprises. PHP-CS-Fixer caches by file hash/mtime. Always --using-cache=no in CI, or a stale cache will happily pass a file that still contains dd().
  • Config API drift. .php_cs + Config::create() is the 2.x style; .php-cs-fixer.php + new Config() is 3.x. If Composer pinned you to 2.x, follow 2.x docs or the config will simply not load — an error that reads like the fixers are missing when they aren't.
  • Extension point: if the built-in list doesn't cover your team's helpers (ray(), dumpDie(), Log::debug), subclass or copy AbstractFixer and mirror the token-matching logic of the existing classes — it's the cheapest way to get a custom "no debug helper in production" rule, and it's why vendoring these classes is usually better than depending on them.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle