dumpio/client

PHP client for the Dumpio dump viewer — sends faithful, typed value dumps and structured messages (exceptions, queries, HTTP, logs, models, …) over HTTP.

Maintainers

Package info

github.com/NyonCode/dumpio-client-php

pkg:composer/dumpio/client

Transparency log

Statistics

Installs: 34

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.5.0 2026-07-09 19:33 UTC

This package is auto-updated.

Last update: 2026-07-09 19:40:38 UTC


README

Send faithful, typed value dumps and structured debug messages (exceptions, SQL queries, HTTP calls, logs, models, …) to the Dumpio viewer. HTTP-first, fire-and-forget, never breaks the host app — every call swallows its own errors and silently drops if the viewer isn't running.

Built to the authoritative client contract in ../BUILDING.md. For a thorough, example-driven walkthrough see docs/GUIDE.md.

Install

composer require dumpio/client

Configuration is read from the environment, or override it at runtime:

Option Env var Default
host DUMPIO_HOST localhost
port DUMPIO_PORT 21234
token DUMPIO_TOKEN ""
enabled DUMPIO_DISABLE (set ⇒ off) true
use Dumpio\Dumpio;

Dumpio::configure(['host' => 'localhost', 'port' => 21234, 'token' => 'secret']);

The basics — var dumps

dio($user, 'user')->green();   // fluent builder (auto-sends); see below
dumpio($user, 'user', 'blue'); // tap-style: sends and returns $user, like tap()
ddio($a, $b);                  // dump every arg, then die
// or: Dumpio::dump($user, 'user'); Dumpio::dd($a, $b);

dio() returns the fluent builder so you can chain color/label/flood control; dumpio() returns the value so you can wrap an expression. Pick by need.

The var serializer uses Reflection, so member visibility (public/protected/private), class names, typed/uninitialized properties and enums are preserved. It breaks cycles via ref nodes and bounds depth/items/string length. The calling file:line is captured automatically.

It also recognises a few common shapes and renders their logical value instead of raw internals: DateTimeInterface becomes a formatted date, an Eloquent model becomes its casted/visible attributes (via attributesToArray()), and a Laravel Collection becomes its items. These checks are by class name, so the core stays framework-agnostic and they are inert when Laravel is absent.

Fluent builder & flood control

dio() (and Dumpio::make()) return a chainable builder. The dump ships on ->send() or automatically when the builder goes out of scope, so ->send() is optional:

dio($user)->red()->label('user')->channel('auth');   // auto-sends
Dumpio::make($payload)->purple()->send();             // explicit send

Colors: red() yellow() blue() gray() purple() pink() green() (or flag('…')), plus label(), channel(), and conditional when($bool) / unless($bool).

Helpers keep loops from flooding the viewer (keyed by call-site file:line, per process — or by an explicit name):

foreach ($rows as $row) {
    dio($row)->once();          // only the first iteration is sent
    dio($row)->limit(5);        // at most 5 are sent
    dio($row)->count();         // one live-updating entry, "×N" in the viewer
    dio($row)->count('rows');   // share one counter across call-sites
}

Time a block with a stopwatch (ships a measure dump with elapsed ms + memory):

$sw = Dumpio::stopwatch('import');
$sw->lap('parsed');   // intermediate split, keeps running
$sw->stop('done');    // final timing

Chainable macros (Laravel)

On Laravel, ->dio() and ->ddio() are registered as macros on query builders and collections, so you can drop a dump mid-chain without breaking it — it ships the current state and returns $this:

User::query()
    ->where('name', 'John')
    ->dio()                              // → query dump (SQL + bindings so far)
    ->whereDate('email_verified_at', '2024-02-15')
    ->dio()                              // → query dump (with the extra clause)
    ->first();

collect($users)->dio('after filter');    // → var dump, returns the collection

->ddio() is the dump-and-die variant. Works on Eloquent\Builder, Query\Builder (DB::table(...)) and Support\Collection. Disable with DUMPIO_REGISTER_MACROS=false.

Typed helpers

Every helper is a static method on Dumpio (fire-and-forget). $opts always accepts envelope overrides: flag, channel, origin.

Helper One-liner
Dumpio::exception(\Throwable $e, array $context = [], array $opts = []) Dumpio::exception($e, ['user' => ['id' => 1]]);
Dumpio::query(string $sql, array $bindings = [], ?float $timeMs = null, array $opts = []) Dumpio::query('select * from users where id = ?', [1], 1.8);
Dumpio::http(string $method, string $url, ?int $status = null, array $opts = []) Dumpio::http('POST', '/api/users', 201, ['body' => $payload, 'responseTime' => 120]);
Dumpio::log(string $level, string $message, array $details = [], array $opts = []) Dumpio::log('warning', 'Auth failed', ['ip' => $ip]);
Dumpio::model(string $class, array $attributes, array $opts = []) Dumpio::model(User::class, $user->getAttributes(), ['exists' => true]);
Dumpio::collection(array $items, array $opts = []) Dumpio::collection($users, ['message' => 'users']);
Dumpio::table(array $columns, array $rows, array $opts = []) Dumpio::table(['id', 'name'], [[1, 'Ada'], [2, 'Linus']]);
Dumpio::measure(string $name, float $timeMs, array $opts = []) Dumpio::measure('render dashboard', 84.2, ['memory' => 2097152]);
Dumpio::performance(array $metrics, array $opts = []) Dumpio::performance(['db_queries' => 12], ['breakdown' => ['database' => 120]]);
Dumpio::event(string $event, array $opts = []) Dumpio::event('order.completed', ['entity' => 'order', 'data' => ['total' => 299.9]]);
Dumpio::trace(?string $label = null, array $opts = []) Dumpio::trace('reached checkout'); — current call stack as a trace dump
Dumpio::memory(?string $label = null, array $opts = []) Dumpio::memory('after import'); — current / peak / limit memory snapshot
Dumpio::html(string $html, array $opts = []) Dumpio::html($renderedView, ['message' => 'Checkout page']);
Dumpio::mail(array $mail, array $opts = []) Dumpio::mail(['subject' => 'Hi', 'to' => ['ada@x.io'], 'html' => $html]);
Dumpio::mailable(object $mailable, array $opts = []) Dumpio::mailable(new OrderShipped($order));

html / mail render foreign markup in the viewer's sandboxed iframe (no scripts, remote resources blocked by default); mail adds a subject/from/to envelope. See the guide.

Flags are picked automatically where it helps: exceptions are red, queries purple, HTTP by status (≥500 red, ≥400 yellow, ≥300 blue, else green), logs by level (error red, warning yellow, info blue).

Two thin global wrappers are also autoloaded for the most common cases:

dumpio_exception($e, ['user' => ['id' => 1]]);
dumpio_query('select * from users', [], 1.2);

Laravel

The service provider is auto-discovered — no manual registration. It reads config('dumpio.*'), configures the static client, and (opt-in) forwards queries and exceptions.

Publish the config:

php artisan vendor:publish --tag=dumpio-config

config/dumpio.php:

return [
    'host' => env('DUMPIO_HOST', 'localhost'),
    'port' => (int) env('DUMPIO_PORT', 21234),
    'token' => env('DUMPIO_TOKEN', ''),
    'enabled' => env('DUMPIO_ENABLED', env('APP_DEBUG', false)), // off in prod
    'listen_queries' => env('DUMPIO_LISTEN_QUERIES', false),     // DB::listen → query dumps
    'listen_exceptions' => env('DUMPIO_LISTEN_EXCEPTIONS', false), // reported exceptions → exception dumps
    'intercept_dumps' => env('DUMPIO_INTERCEPT_DUMPS', false),   // dump()/dd() → the viewer
    'listen_models' => env('DUMPIO_LISTEN_MODELS', false),       // Eloquent created/updated/deleted/restored → model dumps
    'listen_cache' => env('DUMPIO_LISTEN_CACHE', false),         // cache hit/miss/written/forgotten → event dumps
    'listen_jobs' => env('DUMPIO_LISTEN_JOBS', false),           // queue job processing/processed/failed → event dumps
    'listen_events' => env('DUMPIO_LISTEN_EVENTS', false),       // application (non-framework) events → event dumps
    'listen_mail' => env('DUMPIO_LISTEN_MAIL', false),           // outgoing email → mail dumps (rendered preview)
    'intercept_mail' => env('DUMPIO_INTERCEPT_MAIL', false),     // + swallow the real send in dev (Mailpit-style)
    'listen_http_client' => env('DUMPIO_LISTEN_HTTP_CLIENT', false), // outgoing Http:: calls → http dumps
    'listen_livewire' => env('DUMPIO_LISTEN_LIVEWIRE', false),   // Livewire component lifecycle → event dumps
];

When enabled is false (the default in production) the provider configures the client as disabled and registers no listeners — a complete no-op.

Auto-instrumentation (opt-in)

Each switch below is off by default; flip the env var to forward that signal:

Env var What it forwards
DUMPIO_LISTEN_QUERIES every executed SQL query (DB::listen)
DUMPIO_LISTEN_EXCEPTIONS reported exceptions
DUMPIO_INTERCEPT_DUMPS dump() / dd() routed to the viewer (via VarDumper::setHandler) — replaces inline rendering, and dd() still dies
DUMPIO_LISTEN_MODELS Eloquent created / updated / deleted / restored as model dumps (channel models)
DUMPIO_LISTEN_CACHE cache hit / missed / written / forgotten as event dumps (channel cache)
DUMPIO_LISTEN_JOBS queue job processing / processed / failed as event dumps (channel jobs)
DUMPIO_LISTEN_EVENTS your application (non-framework) events as event dumps (channel events)
DUMPIO_LISTEN_MAIL every outgoing email (MessageSending) as a mail dump with rendered preview (channel mail)
DUMPIO_INTERCEPT_MAIL with LISTEN_MAIL: also cancel the real send so dev mail lands only in Dumpio (fake-mail / Mailpit-style)
DUMPIO_LISTEN_HTTP_CLIENT every outgoing Http:: request as an http dump with status + timing (global Guzzle middleware; needs guzzlehttp/guzzle)
DUMPIO_LISTEN_LIVEWIRE Livewire 3 and 4 component mount / action / update / render / island / exception as event dumps (channel livewire; needs livewire/livewire)

Runtime toggles

Config flags only seed the initial state. Any capture can be flipped on or off at runtime — handy inside a test, a Tinker session, or around a suspect block:

Dumpio::showQueries();          // start forwarding queries now
// … the code you want to inspect …
Dumpio::stopShowingQueries();   // and stop

Dumpio::showAll();              // everything on
Dumpio::stopShowingAll();       // everything off

Pairs exist for Queries, Exceptions, Dumps, Models, Cache, Jobs, Events, Mail, HttpClient and Livewire.

Logs → the viewer (Monolog)

Point a log channel at Dumpio\Log\DumpioHandler to stream app logs into the viewer as log dumps (level → flag colour):

// config/logging.php
'channels' => [
    'dumpio' => [
        'driver'  => 'monolog',
        'handler' => \Dumpio\Log\DumpioHandler::class,
    ],
],

Then Log::channel('dumpio')->warning('…'), or add 'dumpio' to a stack channel's channels list to mirror your default log.

Use the helpers anywhere, or the optional facade (also auto-discovered as the Dumpio alias):

use Dumpio\Laravel\Facades\Dumpio;

Dumpio::query($sql, $bindings, $timeMs);
// equivalently: \Dumpio\Dumpio::query(...) or dumpio_query(...)

Set DUMPIO_LISTEN_QUERIES=true to mirror every executed query into the viewer via DB::listen, and DUMPIO_LISTEN_EXCEPTIONS=true to forward reported exceptions through the framework's exception handler.

Symfony

Add the bundle (dev only is recommended):

// config/bundles.php
return [
    // …
    Dumpio\Symfony\DumpioBundle::class => ['dev' => true],
];

The bundle registers Dumpio\Symfony\EventSubscriber\ExceptionSubscriber, which forwards every kernel.exception to the viewer as an exception dump with the current request context. It reads DUMPIO_HOST / DUMPIO_PORT / DUMPIO_TOKEN / DUMPIO_DISABLE from the environment.

The bundle adds more auto-instrumentation when the relevant component is present:

Condition What it forwards
always kernel.exceptionexception dumps with request context
Doctrine DBAL 4 every executed SQL → query dumps (channel database); SQL + timing only, bindings are not captured
symfony/messenger Messenger sent / received / handled / failedevent dumps (channel messenger) — the Symfony equivalent of Laravel's queued-job listeners
symfony/mailer + DUMPIO_LISTEN_MAIL set every outgoing email (MessageEvent) → mail dumps with rendered preview (channel mail)
symfony/http-client + DUMPIO_LISTEN_HTTP_CLIENT set every outgoing request → http dumps with status + timing (non-blocking http_client decorator, channel http)
DUMPIO_INTERCEPT_DUMPS set dump() / dd() routed to the viewer (via VarDumper::setHandler); dd() still dies

The runtime toggles (Dumpio::showQueries() …) and the Monolog handler (Dumpio\Log\DumpioHandler) documented above work the same under Symfony.

Symfony cache pools have no built-in event system (unlike Laravel), so there is no automatic cache forwarding — call Dumpio::event('cache.…', …) yourself if you need it.

Symfony's MessageEvent has no cancel hook, so there is no intercept_mail here — the subscriber only captures mail. To keep dev mail from actually sending, point MAILER_DSN at a null://null transport.

You can also call the static client or helpers from anywhere in your code:

\Dumpio\Dumpio::query($sql, $bindings, $timeMs);
dumpio($entity, 'entity');

See ../BUILDING.md for the full wire contract and the shared var tree format.