Enums, short for "enumerations," are a powerful tool in programming for defining a set of named constants with fixed values. They allow developers to represent a limited and well-defined set of options and improve code readability, maintainability, and type safety. Although PHP lacked native support for enums until version 8.1, there were ways to implement them using libraries or custom classes. In this comprehensive tutorial, we'll cover both pre-PHP 8.1 and PHP 8.1+ approaches to defining and using enums in PHP and Laravel, with real-world examples.
Enums are best suited for constants in your code base that you do not have the need to store in the database but you have them in multiple places in your code. A good example can be checking if a user is an admin, author or a guest. A bad way to write this query can look like
User::where('user_type', 'admin')->get();
You do not need to directly type in the admin
search key every where you need to check for this in the entire code base. If you have the need to change anything then you will need to change it everywhere you have checked for a user type. In cases where you have more than one developer working on the same project, code like this can be prone to bugs. Something as little as miss spelling the first letter of the word in caps can be hard to spot out. Always use Enum
for constants like this.
To use an Enum in laravel at the time of writing this post does not have an artisan command. You just need to create an Enum
folder in the /App
directory of your laravel application and create an Enum
in there like so:
namespace App\Enum;
enum: string {
case BEGINNER = 'beginner';
case INTERMEDIATE = 'intermediate';
case ADVANCE = 'advance';
}
Before PHP 8.1, PHP had no inbuilt support for enums so external packages and libraries were used to work with enums in PHP/Laravel projects. One such popular library is `spatie/enum`. Lets explore a bit on how to use this package. To use this package requires a composer installation using the composer command bellow
composer require spatie/enum
Next, we'll create an enum class that extends the Spatie\Enum\Enum
class to define our custom enum. For example, we'll create a UserRole
enum:
// app/Enums/UserRole.ph
namespace App\Enums;
use Spatie\Enum\Enum;
class UserRole extends Enum
{
public static function admin(): UserRole
{
return new class () extends UserRole {
public function getValue(): string
{
return 'admin';
}
};
}
public static function moderator(): UserRole
{
return new class () extends UserRole {
public function getValue(): string
{
return 'moderator';
}
};
}
public static function user(): UserRole
{
return new class () extends UserRole {
public function getValue(): string
{
return 'user';
}
};
}
}
Now, let's see how we can use our custom UserRole
enum in a Laravel model:
// app/Models/User.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Enums\UserRole;
class User extends Model
{
// ...
public function getRole(): UserRole
{
$roleValue = $this->getAttribute('role'); // Assuming 'role' column stores the role
return UserRole::from($roleValue);
}
public function setRole(UserRole $role)
{
$this->setAttribute('role', $role->value);
}
}
In this example, we have a User
model that uses the UserRole
enum to handle the role
attribute. When retrieving the role from the database, we use the UserRole::from()
method to convert the stored value into an instance of the UserRole
enum. When setting the role, we use the value
property of the enum instance to store the corresponding string value in the database.
Let's use the UserRole
enum to implement user role-based authorization in Laravel.
// app/Http/Middleware/RoleMiddleware.php
namespace App\Http\Middleware;
use Closure;
use App\Enums\UserRole;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class RoleMiddleware
{
public function handle(Request $request, Closure $next, string $role)
{
if (!Auth::check() || Auth::user()->getRole() !== UserRole::from($role)) {
abort(403, 'Unauthorized.');
}
return $next($request);
}
}
Here, we've created a middleware named RoleMiddleware
that checks if the user has the required role to access specific routes. We use the UserRole
enum to compare the user's role to the required role. If the user does not have the correct role, we return a 403 (Forbidden) response.
Starting from PHP 8.1, native support for enums was introduced, eliminating the need for external libraries.
Let's create the UserRole
enum using PHP 8.1+ native support:
// app/Enums/UserRole.php
namespace App\Enums;
enum UserRole {
case Admin;
case Moderator;
case User;
}
Defining enums in PHP 8.1+ is now more concise and clean.
Using the UserRole
enum in the User
model remains the same, regardless of the PHP version:
// app/Models/User.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Enums\UserRole;
class User extends Model
{
// ...
public function getRole(): UserRole
{
$roleValue = $this->getAttribute('role'); // Assuming 'role' column stores the role
return UserRole::from($roleValue);
}
public function setRole(UserRole $role)
{
$this->setAttribute('role', $role);
}
}
In this example, we'll use the ProductStatus
enum to represent the different status of products in an e-commerce application.
// app/Enums/ProductStatus.php
namespace App\Enums;
enum ProductStatus {
case Draft;
case Active;
case OutOfStock;
case Discontinued;
}
In the Product
model:
// app/Models/Product.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Enums\ProductStatus;
class Product extends Model
{
// ...
public function getStatus(): ProductStatus
{
$statusValue = $this->getAttribute('status'); // Assuming 'status' column stores the status
return ProductStatus::from($statusValue);
}
public function setStatus(ProductStatus $status)
{
$this->setAttribute('status', $status);
}
}
In this comprehensive tutorial, we explored the concept of enums in PHP and how to use them in Laravel. We covered two approaches: using a library for PHP versions before 8.1 and utilizing the native PHP 8.1+ enum feature. Enums are powerful tools for creating fixed sets of named constants, leading to more expressive, maintainable, and type-safe code.
Using enums in Laravel models allows for cleaner code and enhances readability and self-documentation. We demonstrated real-world examples of using enums for user roles, product status, and implementing role-based authorization.
Enums can greatly improve your code organization and help prevent bugs by enforcing a clear contract for possible values in your application. Whether you are working with PHP versions before 8.1 or leveraging the new native enum feature, incorporating enums into your Laravel project will undoubtedly enhance your development experience.