PHP Exceptions: Laravel Package Example

PHP Exceptions allow you to replace generic errors with more meaningful error messages to your users and process the errors in a custom way. This tutorial will show a quick example from a Laravel package.

Custom exceptions are a great source of information for framework, package, tool, or module developers.

We're talking about spatie/laravel-permission package - look at the file that uses four custom Exception classes inside.

use Spatie\Permission\Exceptions\GuardDoesNotMatch;
use Spatie\Permission\Exceptions\PermissionDoesNotExist;
use Spatie\Permission\Exceptions\WildcardPermissionInvalidArgument;
use Spatie\Permission\Exceptions\WildcardPermissionNotImplementsContract;
use Spatie\Permission\Guard;
 
// ...
 
public function filterPermission($permission, $guardName = null)
{
// ...
 
if (! $permission instanceof Permission) {
throw new PermissionDoesNotExist();
}
 
return $permission;
}

If the permission doesn't exist in the database, the package throws an Exception. But how is it used, then?


Processing Exceptions

Here's the Exception class itself:

namespace Spatie\Permission\Exceptions;
 
use InvalidArgumentException;
 
class PermissionDoesNotExist extends InvalidArgumentException
{
public static function create(string $permissionName, ?string $guardName)
{
return new static("There is no permission named `{$permissionName}` for guard `{$guardName}`.");
}
 
/**
* @param int|string $permissionId
* @return static
*/
public static function withId($permissionId, ?string $guardName)
{
return new static("There is no [permission] with ID `{$permissionId}` for guard `{$guardName}`.");
}
}

This will immediately tell our end developer that no such permission exists in the database. Now, let's look at a few usages in the Model:

Model

class Permission extends Model implements PermissionContract
{
// ...
 
public static function findByName(string $name, string $guardName = null): PermissionContract
{
$guardName = $guardName ?? Guard::getDefaultName(static::class);
$permission = static::getPermission(['name' => $name, 'guard_name' => $guardName]);
if (! $permission) {
throw PermissionDoesNotExist::create($name, $guardName);
}
 
return $permission;
}
 
public static function findById(int|string $id, string $guardName = null): PermissionContract
{
$guardName = $guardName ?? Guard::getDefaultName(static::class);
$permission = static::getPermission([(new static())->getKeyName() => $id, 'guard_name' => $guardName]);
 
if (! $permission) {
throw PermissionDoesNotExist::withId($id, $guardName);
}
 
return $permission;
}
}

We have two methods here: findByName() and findById(). Both of them will throw an Exception if permission is not found, but they will also provide a custom message that will tell us if that issue is with ID or name.

This is an excellent example of a package developer thinking about the end developer and providing a great experience with custom exceptions and error messages.

We can then catch this Exception individually and make our system react in a specific way if this happens.


You can learn more about exceptions and how to use them in our Handling Exceptions and Errors in Laravel course.

No comments or questions yet...

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 56 courses (1011 lessons, total 46 h 42 min)
  • 77 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials