Back to Course |
PHP for Laravel Developers

Try-Catching Exceptions and PHP Errors

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?


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()
{
$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

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.