You see quite a lot of examples of try-catch with catching a regular Exception
class, like this:
use Exception; try { $request->user()->addMediaFromRequest('avatar')->toMediaCollection();} catch (Exception $e) { Log::debug($e->getMessage());}
But try-catch is way more helpful when catching a specific Exception. Laravel and 3rd party packages often offer us actionable Exception classes for specific 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);}
Notice: try-catch doesn't mean ending the whole method if an Exception happens. In the example above, even if the resizing error occurs, you may still want everything to continue and upload the original, just logging the error to fix it manually in the future.
Let's look at other examples.
Specific and General Exception: Why Not Both
You may catch not only a specific Exception but also add multiple catch
blocks, with the general Exception
class as the last one.
use Illuminate\Validation\ValidationException;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);} catch (Exception $e) { Log::debug($e->getMessage()); throw ValidationException::withMessages([ 'avatar' => __('Selected avatar image failed to upload. Try again or select a different image.'), ]);}
This way, we handle the InvalidManipulation
exception differently than the rest of the exceptions, which allows us to upload the file and show the success screen to the user while still getting log information:
[2023-05-16 08:55:46] production.DEBUG: Width or height or both must be provided[2023-05-16 08:55:46] production.INFO: Please re-run the resizing on user avatar #1
And here's the uploaded image:
Multiple Exceptions in the Same Catch Block
What if you want to catch a few specific exceptions and perform the same action if an error happens? Would you write a few catch
blocks?
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);} catch (FileNotFoundException $fileNotFoundException) { Log::debug($fileNotFoundException->getMessage()); Log::info("Please re-run the resizing on user avatar #" . $request->user()->id);} catch (Exception $e) { Log::debug($e->getMessage()); throw ValidationException::withMessages([ 'avatar' => __('Selected avatar image failed to upload. Try again or select a different image.'), ]);}
Such repeating is not necessary. If more than one Exception is handled with identical code, you can combine them into one catch
block using the |
symbol.
try { $request->user()->addMediaFromRequest('avatar')->toMediaCollection();} catch (InvalidManipulation|FileNotFoundException $exception) { Log::debug($exception->getMessage()); Log::info("Please re-run the resizing on user avatar #" . $request->user()->id);} catch (Exception $e) { Log::debug($e->getMessage()); throw ValidationException::withMessages([ 'avatar' => __('Selected avatar image failed to upload. Try again or select a different image.'), ]);}
As you can see, we are now catching both the InvalidManipulation
and FileNotFoundException
exceptions in the same catch
block. This way, we can handle them the same way but still have different handling for other exceptions.
Please Where can we find the all in built laravel exception to catch and their use case ?
There is no such list, as far as I know