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(){ 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?
Catching a Specific Laravel Exception
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);}
Globally Processing Specific Exception
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); } }); } // ...}
Creating Your Own Exception Class
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(){ 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
PHP Errors vs Exceptions
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.
In the first example provided, you use the method import ($data)
$this->import($data)
, however, in your last try catch statement, you useImportController::importData()
. Is there a connection between the 2 import methods? Does this mean that theImportController
has a static method calledimportData()
and a regular method calledimport($data)
? Are they the same thing (does laravel 'know' a method + a parameter can be directly called as methodParameter())? Or is this a typo?No, it's a basic method in this case, not static. This part is taken from the Handling Exceptions and Errors in Laravel so better refer there for more about exceptions.
Thank you very much!
It would be appropriate to provide information about the "finally" block.
This course/lesson was more focused on the PHP errors and not on overall error handling. We have a separate tutorial about the exceptions, where we talk about
finally
there :)