mindplay/readable
mindplay/readable renders any PHP value—arrays, objects, and scalars—as clean, human-readable, valid PHP-like code that's easy to read and diff, with optional parsing back into values. Handy for debugging, logging, snapshots, and config files.
Install it as a dev dependency if you only use it for local debugging and test diagnostics:
composer require --dev mindplay/readable
If you plan to use it in exception rendering, production log messages, or Artisan command output, install it as a regular dependency instead.
There is no Laravel service provider, facade, config file, or publishable assets. The package is a small plain-PHP utility. Look first at:
vendor/mindplay/readable/README.mdvendor/mindplay/readable/src/Readable.phpThe primary entry points are Readable::value() for formatting a value and Readable::type() for describing its type. A first practical use case is replacing noisy var_dump() / print_r() output while inspecting complex Laravel values:
use mindplay\readable\Readable;
// php artisan tinker
$user = App\Models\User::with('roles.permissions')->first();
dump(Readable::value($user->toArray()));
dump(Readable::type($user));
That is the sweet spot: quickly understanding nested arrays, DTOs, Eloquent attributes, closures, resources, and other values that are awkward to inspect with var_export().
Use Readable::value() when you need a compact human summary rather than a full dump:
use mindplay\readable\Readable;
dump(Readable::value($request->validated()));
dump(Readable::value($job->payload()));
dump(Readable::type($exception));
It is especially useful in php artisan tinker because the output is readable in a terminal, unlike deeply nested var_dump() output.
For structured logs, prefer passing raw arrays to Laravel/Monolog and let the logger normalize them. Use Readable when you need a formatted string inside a message:
use Illuminate\Support\Facades\Log;
use mindplay\readable\Readable;
if (app()->environment('local')) {
Log::debug('Import row rejected', [
'row' => Readable::value($row),
'type' => Readable::type($row),
]);
}
Guard expensive formatting behind an environment or debug check. Building a large readable string eagerly is wasted work if the log level discards it.
Attach readable context to custom exceptions or in your exception handler:
use mindplay\readable\Readable;
throw new InvalidArgumentException(
'Unexpected payload: ' . Readable::value($payload)
);
For broader reporting, format selected context in App\Exceptions\Handler or a custom exception renderer. Keep secrets out of the formatted value before it reaches logs or HTTP responses.
Use it to make PHPUnit/Pest failures easier to understand:
use mindplay\readable\Readable;
$this->assertSame(
$expected,
$actual,
'Actual value: ' . Readable::value($actual)
);
This is particularly helpful for data-provider-driven tests, nested arrays, and DTO comparisons where PHPUnit's default diff is less informative.
Format values for command output:
use mindplay\readable\Readable;
$this->line(Readable::value($report));
$this->line('Type: ' . Readable::type($report));
This works well for diagnostics commands, import/export previews, and local maintenance scripts.
Because Blade escapes {{ }} output, Readable::value() is safe to use in a debug view:
<pre>{{ \mindplay\readable\Readable::value($payload) }}</pre>
Avoid {!! !!} unless you explicitly control the value, since the formatted output is meant for humans and may contain characters that should remain escaped.
Readable is static and has no Laravel integration. If you use it across a codebase, wrap it in a small service or helper so you can add redaction and truncation:
namespace App\Support;
use mindplay\readable\Readable;
final class DebugValue
{
public static function format(mixed $value): string
{
return Readable::value(self::redact($value));
}
private static function redact(mixed $value): mixed
{
// Remove passwords, tokens, authorization headers, etc.
return $value;
}
}
This also gives you a single place to swap the formatter later without touching every call site.
Readable::value() output, use it as a serialization format, or assert against its exact string in tests unless you deliberately want a brittle assertion.$model->toArray() or a selected subset, and ensure relations are loaded if they matter.Readable behind your own service or helper.value() / type() or additional depth/limit options before relying on them.--dev, it will not be present in a production build that runs composer install --no-dev. Install it normally if production exception rendering depends on it.Overall, mindplay/readable is best treated as a lightweight developer-experience utility: valuable for Tinker sessions, test failure messages, local diagnostics, and carefully guarded debug logging, but not a replacement for Laravel's logging, dumping, or exception infrastructure.
How can I help you explore Laravel packages today?