rector/rector-debugging
Debugging utilities for Rector that help you trace which rules match a file and why, inspect transformations, and diagnose unexpected refactoring results when building automated PHP code upgrades.
Install the package as a dev dependency alongside Rector:
composer require --dev rector/rector-debugging
The package ships global helper functions (autoloaded via Composer) that wrap PHP-Parser's NodeDumper and Rector's BetterStandardPrinter. Look at src/functions.php first — that file is the entire API surface, so the README and that file together tell you everything the package does.
The first real use case: you're authoring a custom Rector rule and you don't know what AST node the code you care about produces. Instead of guessing node class names, drop a probe into the refactor() method:
public function refactor(Node $node): ?Node
{
dump_node($node); // inspect node class + structure
return null; // no-op; you're just observing
}
Run Rector in dry-run mode (vendor/bin/rector process src --dry-run) and read the dumped node. Once you see the shape, replace the probe with your actual transformation logic.
Probe → inspect → implement. The dominant workflow is a two-pass loop: first write a rule whose only job is to match and dump nodes (returning null so nothing is written), then implement the real refactor() logic once you understand the AST.
Dump vs. print. dump_node($node) shows you the object graph (class names, properties, child nodes) — use it when you need to know what class a node is or which property holds the sub-expression you want. print_node($node) runs the node back through the printer and gives you valid PHP — use it when you want to confirm which source span the node covers.
Before/after comparisons. When a rule mutates a node, use the paired helpers (print_node_new($old, $new) / dump_node_new(...)) to see the original and the rewritten form side by side. This is the fastest way to catch a rule that "works" but silently drops comments, parentheses, or modifiers.
Scope down with getNodeTypes(). Debug output is only useful if it's not firehosed. Return a specific node class (e.g. [MethodCall::class]) from getNodeTypes() before dumping, and further guard with an instanceof or property check inside refactor() before calling the debug helper.
Combine with --dry-run and --clear-cache. Debugging rules while files are being rewritten makes it hard to compare runs. Always iterate with --dry-run, and clear Rector's cache between edits so you're not looking at stale results.
Node-list helpers. For rules that operate on arrays of nodes (e.g. adding statements to a ClassMethod), use the list-oriented print helper to render the whole collection rather than mapping over each node yourself.
require-dev. These are debug helpers; they should never end up in a production dependency tree. If you're on a shared codebase, verify nobody promoted it to require.dd-style helpers halt execution. If you use a dump-and-die variant, the rest of your rule set and all other files stop processing — expected, but easy to mistake for a crash when running Rector across a whole directory.print_node goes through BetterStandardPrinter; attribute-based metadata (comments, origNode, format-preserving flags) can look different from the original source. Don't use printed output as ground truth for comment preservation — test with a real fixture.composer dump-autoload; the functions are registered via Composer's files autoload, and a stale autoloader is the usual cause.--clear-cache before assuming the rule is wrong.tests/ bootstrap — they're thin wrappers around NodeDumper and BetterStandardPrinter, and vendoring them means one less dev dependency to track.How can I help you explore Laravel packages today?