ekino/phpstan-banned-code
PHPStan extension that detects banned code in your project, like var_dump, exit, eval, print, shell execution, and other unwanted functions. Configure the exact nodes and functions to block, enforce rules in CI, and keep your codebase clean.
dd(), dump(), var_dump(), print_r(), exit/die, eval, echo/print, backticks, or process-execution functions like shell_exec/exec/system/proc_open. Buying costs one dev-only Composer dependency plus a NEON config block inside PHPStan we already run; building means authoring and maintaining a custom PHPStan rule, its tests, and its PHPStan-version upgrade treadmill. Unless we need policy PHPStan configs can't express, buy.dd() and dump() are the single most idiomatic Laravel debugging habit and the most common way a debug statement reaches a shared branch or a demo environment. If postmortems, QA escapes, or "why is the API returning an empty 200" tickets trace back to a stray dd(), this reframes the fix from "be more careful in review" to "add a deterministic CI gate" — a prevention investment with a measurable success metric (zero debug-leftovers merged per quarter).eval, shell_exec, exec, passthru, system, proc_open, phpinfo form a defensible starting denylist. In a SOC2/PCI-style questionnaire this is evidence of an automated technical control rather than a written policy — valuable, provided we don't oversell it as injection prevention. It is one control among several (the others being disable_functions, container hardening, SAST/DAST).use_from_tests rule bans use Tests\... imports from non-test files — a cheap, high-signal guard against test doubles, factories, and fixture helpers leaking into production code. Worth a decision in its own right if we've ever shipped test scaffolding.non_ignorable: true default is the most product-relevant feature in the package: violations cannot be quietly absorbed into a PHPStan baseline. That is the difference between a lint suggestion and an enforceable policy, and it should drive how we configure the gate (set it deliberately, not by accident).Adopt when:
exit/die in request paths, shell/process functions in application code, or deprecated calls during an upgrade.Look elsewhere or handle differently when:
nikic/php-parser script covers the same ground; the rules themselves are trivial to reimplement.call_user_func('shell_exec', ...), variable functions, or reflection-heavy code. It must not substitute for disable_functions in php.ini, container hardening, or SAST/DAST. Frame it internally as defense-in-depth, not defense.exec in a deploy console command, or dump() in a local-only debug helper), severity tiers, or auto-fix. Multiple PHPStan config files can approximate per-scope policy; the rest is out of scope and would argue for a custom rule.One line: A tiny, free PHPStan extension that turns "no debug leftovers, no unsafe eval/shell calls, no deprecated constructs" into an automatically enforced build failure instead of a code-review hope.
For executives:
eval calls in application code — and produces evidence an auditor will recognize as an automated technical control.For engineering:
phpstan/extension-installer it's zero-wiring, otherwise one includes: line. Configure the banned set in NEON — functions (dd, dump, var_dump, print_r, exec, shell_exec, system, passthru, proc_open, phpinfo) and language constructs (Stmt_Echo, Expr_Eval, Expr_Exit, Expr_Print, Expr_ShellExec).use_from_tests to stop Tests\... imports leaking into production code. Keep non_ignorable at its default true; treat any exception as a reviewed, temporary change.exec in deploy tooling, express that as a config boundary rather than weakening the rule globally.How can I help you explore Laravel packages today?