buggregator/trap
Buggregator Trap transforms PHP debugging: drop-in Symfony VarDumper extensions, helper functions for any Buggregator server, and a lightweight local server that needs no Docker. Install as a Composer dev dependency; pairs with the Buggregator PHPStorm plugin.
Trap 1.18+ requires PHP 8.2. Confirm your Laravel runtime before installing:
php -v
If the app is still on PHP 8.1, pin an earlier Trap release compatible with your PHP version or run Trap from a separate PHP 8.2+ environment.
Install as a dev dependency in the Laravel project:
composer require --dev buggregator/trap -W
Start the Trap server in a dedicated terminal:
vendor/bin/trap
Keep that process running while you develop. Then use the trap() helper in a controller, Artisan command, Tinker session, job, or service:
Route::post('/orders', function (Request $request) {
trap($request->all())->depth(3);
return response()->json(['ok' => true]);
});
First places to look:
trap(), tr(), and td().vendor/bin/trap — trapped messages appear there.1025.A good first Laravel use case is API debugging: use trap() instead of dd() so you can inspect request payloads without killing the response. For fluent debugging, tr($value) dumps and returns the value, which is useful inside pipelines:
$payload = tr($request->validated());
If you need to stop execution, td($value) dumps and dies.
Use trap() as a non-destructive dump() replacement.
Laravel’s dump() and dd() still work, but trap() is the explicit API for sending rich debug payloads to the Trap server. Use it when you want the request lifecycle to continue:
trap($order)->depth(4);
trap($order, user: $order->user, items: $order->items);
Use tr() in pipelines and service layers.
tr() is effectively trap(...)->return(), so it fits naturally in Laravel code that expects a returned value:
$normalized = tr($this->normalize($input));
return $this->processor->handle(tr($normalized));
Use td() for hard stops in API and CLI contexts.
Because td() sends the dump to Trap and then exits, it avoids dumping HTML into a JSON response or browser output:
td($request->all());
Use Trap’s chainable controls to reduce noise.
Large Laravel payloads, collections, and models can produce enormous dumps. Limit them early:
trap($veryDeepArray)->depth(3);
foreach ($veryLargeCollection as $item) {
trap($item)->times(3);
}
trap($animal)->once()->if($animal instanceof Cat);
Use no-argument tr()/td() for lightweight tracing.
They show a short stack trace, memory usage, and time between calls, which is useful for profiling request flow without a full profiler:
public function handle($input)
{
tr(); // Trace #0
$data = $this->prepareData($input);
tr(); // Trace #1 with timing/memory delta
$this->processor->process(tr(data: $data));
td(); // Trace #2 and exit
}
Run Trap alongside Artisan, queues, and Tinker.
Typical local workflow:
# Terminal 1
vendor/bin/trap
# Terminal 2
php artisan serve
# Terminal 3
php artisan queue:work
Then debug HTTP requests, queued jobs, and Tinker experiments from the same Trap terminal. For long-running queue workers, restart the worker after changing Trap-related environment or mail configuration.
Trap outgoing mail in Laravel.
Point Laravel’s local SMTP settings at Trap’s mail port:
MAIL_MAILER=smtp
MAIL_HOST=127.0.0.1
MAIL_PORT=1025
Then trigger a Mailable, notification, or password reset and inspect it in the Trap terminal. If you prefer files, use Trap’s mail-to-file sender; it creates per-recipient folders such as runtime/mail/[email protected] and saves messages as JSON.
Choose senders for different workflows.
By default Trap shows dumps in the console. You can combine senders:
vendor/bin/trap -sconsole -sfile
Use file for headless debugging or when you want a durable record. Use server when sending to a remote Buggregator server instead of the local mini-server. If you use body-to-file capture, inspect individual files rather than assuming all bodies from a batch are combined; Trap 1.18 writes each body in a batch to its own file.
Use Trap for non-VarDumper traffic where relevant.
Trap can act as a local trap for Monolog, Sentry, SMTP, HTTP dumps, Ray, and raw data. In Laravel projects this is most immediately useful for SMTP/mail testing and for centralizing debug output from Symfony VarDumper-based tooling. For framework-specific handlers such as Monolog or Sentry, follow the Buggregator documentation rather than inventing Laravel log-channel configuration from scratch.
Use the PhpStorm plugin for IDE-adjacent debugging.
If you already use PhpStorm, the Buggregator plugin can make Trap part of the normal debug loop rather than a separate terminal-only tool.
Use the Phar or global binary when Composer conflicts appear.
If Trap’s dependencies conflict with the Laravel project, install it as a Phar:
wget https://github.com/buggregator/trap/releases/latest/download/trap.phar
chmod +x trap.phar
./trap.phar --version
Or install globally with Dload:
dload get trap
Containerized Laravel apps need host networking adjustments.
If Laravel runs inside Docker and Trap runs on the host, 127.0.0.1 inside the container points at the container, not your machine. Use host.docker.internal for SMTP/Trap host settings, or run Trap in a way that is reachable from the container. If Trap must listen beyond localhost, set TRAP_TCP_HOST deliberately and do not expose it publicly.
php -v first. On PHP 8.1, pin an older Trap release or use a separate PHP 8.2+ runtime.trap() produces no output, first confirm vendor/bin/trap is active and listening. A missing Trap process is the most common cause of “silent” dumps. In 1.18+, startup errors should exit with a non-zero code, so check the Trap terminal rather than assuming the command is running.9912, 9913, 1025, and 8000. Laravel’s php artisan serve also defaults to 8000, so change one side: run Artisan on another port or start Trap with explicit ports such as vendor/bin/trap -p9912.TRAP_TCP_PORTS, TRAP_TCP_HOST, and TRAP_UI_PORT. Put these in your local shell or project-specific script rather than relying on remembered CLI flags.trap() explicitly targets the Trap server; dump() may not. Installing Trap enhances Symfony VarDumper behavior, but when you want output in the Trap terminal, prefer trap(), tr(), or td() over assuming Laravel’s existing dump() calls will be routed there.trap() may set REMOTE_ADDR and REMOTE_PORT automatically. The README notes this happens when those server values are not already set. If your code depends on those values, inspect them before assuming they reflect the real request.MAIL_MAILER=smtp, MAIL_HOST, and MAIL_PORT=1025 for local trapping. If Laravel still sends real mail, clear cached config with php artisan config:clear and confirm the active .env for that process.php artisan config:clear and restart queue:work or Octane workers. Long-running PHP processes do not automatically pick up new environment values.-sfile. Do not assume the console output is captured somewhere later.mail-to-file writes under runtime/mail. That is useful for inspecting rendered mail, but treat it as debug output. Do not commit those files or depend on them as production mail storage.td() stops the process. In web requests this can produce an incomplete response; in API/JSON contexts prefer trap() when the response must still be returned. Use td() deliberately for hard stops.->depth(), ->times(), and ->once() aggressively.trap($var, foo: $far, bar: $bar) is often more readable than dumping an ad hoc array, especially when debugging several related values.127.0.0.1 is usually wrong. Use host.docker.internal where appropriate, or run Trap inside the same network namespace with an intentional host binding.--ui mode is not the thing to depend on. The README describes the Docker-free web UI as a feature in development. For day-to-day reliability, treat the terminal Trap server as the stable workflow.composer require --dev buggregator/trap -W creates version conflicts in a large Laravel app, use the Phar or global binary instead of forcing dependency changes.tr() deltas. If you previously avoided those paths, they are more trustworthy now.trap() API for routine needs before writing custom integration code.How can I help you explore Laravel packages today?