Exceptions are the mechanism to catch some invalid behavior and gracefully handle them instead of just showing "500 server error" to the users.
Take a look at this example:
public function __invoke(){ $data = [['name' => 'John Doe', 'email' => 'email@email.com', 'date' => '23-04']]; try { $this->import($data); } catch (ImportHasMalformedData $e) { return redirect()->route('dashboard')->with('message', 'Uh oh, the import has failed. Try again later or contact support'); } return 'Imported';}
This snippet means that in case of ANY Exception, the user would get redirected back and see the error message.
But what if we're expecting something specific to happen?
Try-catch is way more helpful when catching a specific Exception. Laravel and 3rd party packages often offer us actionable Exception classes for particular errors.
For example, when uploading a picture, you might have some issues with resizing the image. For that, there's a specific InvalidManipulation
.
use Spatie\Image\Exceptions\InvalidManipulation;use Exception; try { $request->user()->addMediaFromRequest('avatar')->toMediaCollection();} catch (InvalidManipulation $manipulationException) { Log::debug($manipulationException->getMessage()); Log::info("Please re-run the resizing on user avatar #" . $request->user()->id);}
There are cases when, for a specific Exception, you will always want to render the same result.
For example, only for routes with /api
and if Exception is NotFoundHttpException
to show some general message.
app/Exceptions/Handler.php:
use Illuminate\Http\Request;use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class Handler extends ExceptionHandler{ // ... public function register(): void { $this->renderable(function (NotFoundHttpException $e, Request $request) { if ($request->is('api/*')) { return response()->json(['message' => 'Record not found.'], 404); } }); } // ...}
To create a custom Exception in Laravel, you need to run a single command:
php artisan make:exception ImportHasMalformedData
It will create a new file in app/Exceptions/ImportHasMalformedData.php
.
app/Exceptions/ImportHasMalformedData.php:
class ImportHasMalformedData extends Exception{ protected $message = 'The import has malformed data.';}
Now, throwing this Exception will result in a more actionable message:
use App\Exceptions\ImportHasMalformedData; // ... public function __invoke(){ $data = [['name' => 'John Doe', 'email' => 'email@email.com', 'date' => '23-04']]; try { $this->import($data); } catch (ImportHasMalformedData $e) { return 'Malformed data'; } return 'Imported';}
Running this, we will have the following output in our browser:
Malformed data
In addition to Exceptions, there are also PHP errors to catch, those are different things! Sometimes, you need to handle PHP errors. For example, this message:
While this isn't an Exception, you can still manage them like they are.
try { $this->importData();} catch (\Exception $e) { dd("General Exception: " . $e->getMessage());} catch (\Error $e) { dd("General error: " . $e->getMessage());}
public function importData($row){ // ...}
That way, you can catch the PHP Error just like an Exception:
You can do this for all the errors in the official PHP documentation.