yiisoft/friendly-exception
User-friendly exception handling for PHP apps: convert throwables into readable messages, safe debug views, and structured data for logs/HTTP responses. Helps present errors clearly in production while keeping rich context for developers.
Installation
composer require yiisoft/friendly-exception
Add to composer.json if using Yii:
"yiisoft/friendly-exception": "^1.0"
Basic Usage
For Laravel, register the exception handler in app/Exceptions/Handler.php:
use Yiisoft\FriendlyException\ExceptionHandler;
public function register()
{
$this->renderable(function (Throwable $e) {
return (new ExceptionHandler())->handle($e);
});
}
First Use Case Trigger an exception in a route:
Route::get('/test-error', function () {
throw new \RuntimeException('Test error for debugging');
});
Visit /test-error to see a formatted error page with:
Environment-Specific Rendering
Use ExceptionHandler with environment checks:
$handler = new ExceptionHandler();
if (app()->environment('local')) {
$handler->setDebugMode(true);
}
Custom Error Pages
Extend Renderer to modify output:
use Yiisoft\FriendlyException\Renderer\Renderer;
class CustomRenderer extends Renderer
{
protected function renderException(Throwable $exception): string
{
return "<div class='custom-error'>" . parent::renderException($exception) . "</div>";
}
}
Integration with Laravel’s Exception Handler
Override render() in Handler.php:
public function render($request, Throwable $exception)
{
return (new ExceptionHandler())->handle($exception);
}
Logging Exceptions Combine with Laravel’s logging:
$handler = new ExceptionHandler();
$handler->setLogger(\Log::channel('single'));
StackTraceRenderer for syntax-highlighted code snippets.APP_ENV to control verbosity:
$handler = new ExceptionHandler(['debug' => app()->isLocal()]);
class DebugExceptionMiddleware
{
public function handle($request, Closure $next)
{
try {
return $next($request);
} catch (Throwable $e) {
return (new ExceptionHandler())->handle($e);
}
}
}
Production Safety
debug: false in non-local environments:
$handler = new ExceptionHandler(['debug' => false]);
APP_DEBUG env var:
$handler = new ExceptionHandler(['debug' => (bool) env('APP_DEBUG')]);
Stack Trace Truncation
$handler = new ExceptionHandler(['maxStackTraceLines' => 20]);
Yii Integration Conflicts
ErrorHandler may override Laravel’s exception handling.
Fix: Disable Yii’s handler if using Laravel:
Yii::$container->set(ErrorHandler::class, new class extends ErrorHandler {
public function handleException($exception): void { /* Custom logic */ }
});
php artisan view:clear
dd() on the renderer to debug output:
$renderer = new Renderer();
dd($renderer->renderException($exception));
errors views in resources/views to embed friendly-exception output.Add Context Data Attach custom data to exceptions:
$exception = new \RuntimeException('Failed', 0, null);
$exception->setContext(['user_id' => auth()->id()]);
Render it in a custom renderer:
$context = $exception->getContext();
echo "<pre>User ID: {$context['user_id']}</pre>";
Plugin System
Extend Renderer to add tabs or sections:
class PluginRenderer extends Renderer
{
protected function renderTabs(Throwable $exception): string
{
return '<div class="plugin-tab">Custom Data</div>';
}
}
API Error Responses Return JSON for APIs:
$handler = new ExceptionHandler(['format' => 'json']);
return response()->json($handler->handle($exception));
How can I help you explore Laravel packages today?