paragonie/corner
Corner provides extended PHP exceptions/errors with richer context: helpful long-form messages, source code snippets around the failure, and support links. Inspired by Rust-style diagnostics, useful even outside UI error pages.
Installation:
composer require paragonie/corner
Ensure your project uses PHP 7.1+ (or PHP 5.4+ for v1.x).
Basic Usage:
Replace native exceptions with Corner\Exception or Corner\Error:
use Corner\Exception;
try {
throw new Exception('Something went wrong');
} catch (Exception $e) {
echo $e->getHelpfulMessage(); // Detailed explanation
echo $e->getSnippet(); // Surrounding code snippet
}
First Use Case:
Replace Laravel’s default Handler to log/render Corner exceptions:
// app/Exceptions/Handler.php
use Corner\Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
class Handler extends ExceptionHandler {
public function render($request, Throwable $exception) {
if ($exception instanceof Exception) {
return response()->json([
'error' => $exception->getHelpfulMessage(),
'snippet' => $exception->getSnippet(),
]);
}
return parent::render($request, $exception);
}
}
Custom Exception Hierarchy:
Extend Corner\Exception for domain-specific errors:
class DatabaseConnectionException extends Exception {
public function getHelpfulMessage() {
return "Database connection failed. Check your `.env` file for `DB_HOST`, `DB_PORT`, and `DB_PASSWORD`.";
}
public function getSupportLink() {
return 'https://laravel.com/docs/database#configuration';
}
}
Dynamic Snippets:
Use getSnippet() to debug runtime issues:
try {
$user = User::findOrFail($id);
} catch (ModelNotFoundException $e) {
echo $e->getSnippet(2, 2); // Show 2 lines before/after the error
}
Logging Integration:
Log Corner exceptions with context:
use Illuminate\Support\Facades\Log;
try {
// Risky operation
} catch (Exception $e) {
Log::error($e->getHelpfulMessage(), [
'snippet' => $e->getSnippet(),
'support_link' => $e->getSupportLink(),
]);
}
API Responses: Return structured error payloads:
return response()->json([
'status' => 'error',
'message' => $e->getHelpfulMessage(),
'code' => $e->getCode(),
'debug' => app()->isLocal() ? $e->getSnippet(3, 3) : null,
]);
Middleware for Errors:
Catch Corner\Error (non-exception errors) globally:
// app/Http/Kernel.php
protected $errorMiddleware = [
\App\Http\Middleware\HandleCornerErrors::class,
];
Performance Overhead:
getSnippet() reads source files dynamically. Avoid calling it in hot paths (e.g., loops).PHP 8+ Compatibility:
Throwable methods may behave differently.parent::__construct() explicitly in custom exceptions to avoid deprecation warnings.Source File Access:
getSnippet() fails if:
Corner\FileNotFoundException gracefully:
try {
$snippet = $e->getSnippet();
} catch (FileNotFoundException $e) {
$snippet = "Could not locate source file: {$e->getMessage()}";
}
Stack Trace Depth:
getSnippet($traceWalk) may return empty strings for deep stack traces.$traceWalk to avoid excessive file I/O.Inspect Stack Traces:
Use getTraceAsString() as a fallback for complex errors:
echo $e->getHelpfulMessage() ?: $e->getTraceAsString();
Custom Error Templates:
Override getHelpfulMessage() to include:
php artisan cache:clear").Testing:
Mock getSnippet() in unit tests:
$exception = $this->getMockBuilder(Exception::class)
->onlyMethods(['getSnippet'])
->getMock();
$exception->method('getSnippet')->willReturn('mocked snippet');
Add Metadata: Extend exceptions with custom properties:
class ValidationException extends Exception {
public function __construct(array $errors) {
parent::__construct('Validation failed');
$this->errors = $errors;
}
public function getHelpfulMessage() {
return "Validation errors:\n" . print_r($this->errors, true);
}
}
Localization:
Support multiple languages in getHelpfulMessage():
public function getHelpfulMessage() {
return __($this->getMessage(), [], 'errors');
}
Integration with Laravel:
Corner exceptions in validate() rules:
$validator->errors()->add('email', new EmailValidationException($email));
App\Exceptions\Handler to format Corner exceptions for the debugbar.How can I help you explore Laravel packages today?