Enums provide a way to define a group of related values essentially becoming a self-contained "box of constants". The feature was introduced in PHP 8.1 so it has been around for a while now.
Before Enums, you'd often resort to constants for this kind of data. Imagine your website had user types e.g. Newbie
, User
, Moderator
and Admin
. Assuming you had a class for your User model, you could do something like this:
1class User2{3 const NEWBIE_TYPE = 'newbie';4 const USER_TYPE = 'user';5 const MOD_TYPE = 'moderator';6 const ADMIN_TYPE = 'admin';7}
By using Enums, you can extract these to its own file and that would look like this:
1enum UserType: string2{3 case NEWBIE = 'newbie';4 case USER = 'user';5 case MOD = 'moderator';6 case ADMIN = 'admin';7}
Which you can then access like so:
1$value = UserType::ADMIN->value; // admin
If you're not familiar with Enums then this will probably seem like only a slight improvement. But Enums come with a whole bag full of features.
Enums can also have their own methods which opens up so many possibilities. e.g. you can add any kind of helper methods to your Enum like this:
1public function label(): string 2{ 3 return match ($this) { 4 self::NEWBIE = 'Newbie'; 5 self::USER = 'User'; 6 self::MOD = 'Moderator'; 7 self::ADMIN = 'Administrator'; 8 default => 'Undefined', 9 };10}
And then access it like this:
1$label = UserType::MOD->label(); // Moderator
You can also easily loop through them by using the built in method cases()
if you need to, for instance, display a dropdown with all the available options.
1<select name="user_type">2 @foreach(UserType::cases() as $userType)3 <option value="{{ $userType->value }}">4 {{ $userType->label() }}5 </option>6 @endforeach7</select>
Enums are a PHP feature so you can use it anywhere you want whether you're using a framework or not. As you may expect though, Laravel does come with a few features of its own that take advantage of Enums, my favourite one being the use of it in validation. For instance, if you're validating the dropdown above, you can easily do it like so and Laravel will check if the provided option matches a valid enum value.
1use App\Enums\UserType;2use Illuminate\Validation\Rule;3 4$request->validate([5 'user_type' => [Rule::enum(UserType::class)],6]);
If you're like me and you're constantly creating new enums in your projects, then having a dedicated script to automate things might be worth it. Laravel allows you to create your own artisan
commands and you can even make it look like one of its native commands, if you're feeling fancy.
Our custom artisan command is going to generate an Enum file for us but to do that, it needs a template so we'll have to create one first; so we'll create it as stubs/enum.stub
, in the project root directory. If you decide to customise Laravel's own make
commands, this is where those stubs will be published so this is the perfect place to do it.
1<?php 2 3namespace App\Enums; 4 5enum {{ name }}: string 6{ 7 case TEST = 'test'; 8 9 /**10 * @return string11 */12 public function label(): string13 {14 return match ($this) {15 self::TEST => 'Test',16 };17 }18 19 /**20 * Always remember to use this method instead of the default cases() as this will allow you21 * to filter out the cases you don't want to show in the frontend while still keeping them22 *23 * @return {{ name }}[]24 */25 public static function all(): array26 {27 return [28 self::TEST,29 ];30 }31}
This is just a simple template but you can customise it as much as you want. e.g. I always like to have an all()
method available where I return only the constants being actively used in the project as opposed to using the built in method cases()
which returns every single constant in the Enum. This can be very useful in case you need to deprecate one of the constants and filter those out in a user facing page, for instance, as all you have to do is to remove it from the all method and no other code changes are needed.
Now that we have our stub, it's time to create the actual script. So we'll run this to create our own command and we'll call it MakeEnum
;
1php artisan make:command MakeEnum
Running this command will generate a new class named MakeEnum
in app\Console\Commands
which you can then customise like so.
1<?php 2 3namespace App\Console\Commands; 4 5use Illuminate\Console\Command; 6use Illuminate\Filesystem\Filesystem; 7 8class MakeEnum extends Command 9{10 /**11 * The name and signature of the console command.12 *13 * @var string14 */15 protected $signature = 'make:enum {name}';16 17 /**18 * The console command description.19 *20 * @var string21 */22 protected $description = 'Make an Enum file';23 24 /**25 * @var Filesystem26 */27 protected Filesystem $files;28 29 public function __construct(Filesystem $files)30 {31 parent::__construct();32 33 $this->files = $files;34 }35 36 /**37 * Execute the console command.38 */39 public function handle(): void40 {41 $path = base_path('App\\Enums\\'.$this->argument('name').'.php');42 43 $contents = $this->getSourceFile();44 45 if (! $this->files->exists($path)) {46 $this->files->put($path, $contents);47 $this->info("File : {$path} created");48 } else {49 $this->info("File : {$path} already exists");50 }51 }52 53 /**54 * Get the stub path and the stub variables55 *56 * @return string|array|bool57 */58 public function getSourceFile(): string|array|bool59 {60 return $this->getStubContents(61 __DIR__.'/../../../stubs/enum.stub',62 [63 'name' => $this->argument('name'),64 ]65 );66 }67 68 /**69 * Replace the stub variables(key) with the desire value70 *71 * @param $stub72 * @param array $stubVariables73 * @return string|array|bool74 */75 public function getStubContents($stub, array $stubVariables = []): string|array|bool76 {77 $contents = file_get_contents($stub);78 79 foreach ($stubVariables as $search => $replace) {80 $contents = str_replace('{{ '.$search.' }}', $replace, $contents);81 }82 83 return $contents;84 }85}
NOTE: If you wish to place your custom command somewhere else then you'll have to register it manually by doing this.
And there you have it! From now on, you can simply run php artisan make:enum MyAwesomeEnum
and you'll have your brand new Enum waiting for you.
*Code highlighting provided by Torchlight.