oodle/krumo
oodle/krumo is a PHP debugging aid that replaces var_dump() and print_r() with a collapsible, color-coded tree view of arrays and objects. Expand and collapse nodes to inspect complex variables quickly and keep debug output readable in any PHP project.
Krumo is a standalone PHP dumper — not a Laravel package. There is no service provider, facade, config publish, or auto-discovery. Treat it as a drop-in library, not a framework citizen.
Install
composer require oodle/krumo --dev
If the fork has no composer.json autoload entry (likely, given its heritage), drop the krumo/ directory into your project and require_once base_path('krumo/init.php'); from a dev-only helper.
First place to look
README / examples/ directory — the fork's "new features" are the whole reason to pick it over upstream, and they are usually only documented there.krumo/class.krumo.php for the public surface: krumo::dump(), krumo::show(), krumo::print_r(), and the KRUMO_* constants (KRUMO_RETURN, KRUMO_EXPAND, KRUMO_VERBOSE).krumo::$config for the runtime options (skin, sorting, URL/path to assets).First use case Open a dev-only route and dump a real payload:
Route::get('/_debug/users', function () {
abort_unless(app()->environment('local'), 404);
$orders = \App\Models\Order::with('customer', 'items')->latest()->limit(5)->get();
krumo($orders); // renders the collapsible HTML tree into the response
});
This is the canonical Krumo workflow: an HTTP response you look at, with nested objects and arrays expandable in place.
Guard everything behind local. Krumo has no built-in environment awareness, so wrap it in a project helper:
if (! function_exists('kd')) {
function kd(mixed $value, ?string $name = null): void
{
if (! app()->environment('local') || ! class_exists('krumo')) {
return; // or dump() in non-local
}
krumo($value, $name);
}
}
Capture instead of echoing. Because Krumo writes straight into the output buffer, use KRUMO_RETURN when you need the markup inside a view or a response object:
$html = krumo($payload, 'payload', KRUMO_RETURN);
return response($html); // standalone debug page
// or: return view('debug', compact('html'));
In Blade: {!! krumo($user, null, KRUMO_RETURN) !!} — but emit krumo::css() / krumo::js() once in the layout rather than letting each dump inline its own assets, or you get duplicated <style>/<script> blocks on pages with many dumps.
Snapshot-and-compare debugging. Krumo's strength is that it preserves the full tree inline, so a cheap pattern is dumping the same variable at several points in a request — before/after a transformation — and eyeballing the two trees on one page:
kd($request->all(), 'input');
$data = $this->service->transform($request->all());
kd($data, 'after transform');
This is where Krumo still holds up against dd(): nothing halts execution, so you get a timeline instead of a single frame.
Inspect what Laravel hides. Eloquent models, $model->getAttributes(), relation objects, config() arrays, and $request->headers all render as expandable trees; recursion (model ↔ parent relations, container bindings) is handled by Krumo's depth guard rather than blowing the page up.
Pair with Telescope/Debugbar, don't replace it. Use Krumo for one-off structural inspection; keep Telescope for request history and queries. Krumo has no query log, no timeline, no storage — it is purely a value renderer.
artisan tinker, queue workers, scheduled commands, phpunit, and any JSON/API route. If your dump target isn't a browser response, fall back to dump()/logger().krumo() in a controller that returns JSON or a redirect prepends markup to the body or triggers "headers already sent". Never leave a Krumo call on a path that can be hit by an API consumer.env(), API keys, password hashes, and session tokens. Environment gate + APP_DEBUG gate is non-negotiable; also strip .env values from anything you paste into an issue.dir and url in krumo::$config explicitly (e.g. url = asset('vendor/krumo'), with the files published/copied there). This is the most common "Krumo is broken" symptom and it has nothing to do with the dump itself.Collection of 500 models with relations produces megabytes of nested markup. Always limit()/->take() and prefer ->toArray() on the subset you actually need. KRUMO_EXPAND on a big tree makes it worse — expand lazily.krumo() function and krumo class land in the root namespace. In a Laravel app this is tolerable (no collision with Symfony's dump/dd), but it means the package is not isolated; don't assume you can autoload it out of the way.config/krumo.php, no .env toggles, no publish tag. Any configuration is imperative (krumo::$config[...] = ...) and must run before the first dump — put it in a service provider's register() wrapped in if (app()->environment('local')).composer.json; there is no release cadence to rely on and "new features" in the fork are undocumented behaviour, not a contract.symfony/var-dumper, which renders collapsible HTML dumps with far better CLI support and zero install cost. Krumo's only genuine edges are the multi-dump/timeline style and the specific skin UI — if neither matters to you, dump() and Ray are the lower-risk default.How can I help you explore Laravel packages today?