Enums
Chapter Overview
In this chapter you will learn:
- What Enums are
- Why Enums exist
- Problems Enums solve
- Unit Enums
- Backed Enums
- Enum Methods
- Enum Interfaces
- Enum Traits
- Enum Best Practices
- Enterprise Examples
- PocketMine Examples
- Projects and Exercises
Introduction
Enums were introduced in:
PHP 8.1
Enums are one of the biggest additions to PHP.
Before Enums existed, developers used:
const ADMIN = "admin";
const MOD = "mod";
const PLAYER = "player";
This created many problems.
What is an Enum?
Enum means:
Enumeration
An enum is a fixed list of possible values.
Example
Traffic Lights:
RED
YELLOW
GREEN
Only these values exist.
You cannot create:
PURPLE
BLUE
BLACK
because they are invalid.
This is exactly how enums work.
Real Life Examples
Enums are everywhere.
Examples:
Game Modes
Payment Status
User Roles
Packet Types
Permission Levels
Order Status
Server States
Problem Without Enums
Example:
$status = "compeleted";
Notice:
compeleted
Typo.
PHP accepts it.
Your application breaks.
Another example:
$rank = "admn";
Again invalid.
No error.
Enums Solve This
enum Rank {
case ADMIN;
case MODERATOR;
case PLAYER;
}
Now:
$rank = Rank::ADMIN;
No typos.
Much safer.
Benefits of Enums
✅ Type Safety
✅ Better Readability
✅ Auto Completion
✅ Fewer Bugs
✅ Cleaner Architecture
Basic Syntax
Unit Enum
enum Rank {
case OWNER;
case ADMIN;
case PLAYER;
}
Usage:
$rank =
Rank::OWNER;
Comparison:
if (
$rank === Rank::OWNER
) {
}
Visualization
Rank
│
├── OWNER
├── ADMIN
└── PLAYER
Unit Enums
Unit enums contain:
Cases only.
No values.
Example:
enum ServerState {
case STARTING;
case RUNNING;
case STOPPING;
case OFFLINE;
}
Usage:
$state =
ServerState::RUNNING;
Why Useful?
Because:
Only valid states can exist.
Backed Enums
Backed enums store values.
Example:
enum Rank : string {
case OWNER = "owner";
case ADMIN = "admin";
case PLAYER = "player";
}
Usage:
echo
Rank::OWNER->value;
Output:
owner
Integer Backed Enum
enum Permission : int {
case PLAYER = 1;
case VIP = 2;
case ADMIN = 3;
}
Output:
Permission::ADMIN->value
Result:
3
Why Backed Enums Exist
Useful for:
Databases
Configurations
JSON APIs
Packets
Files
Example Database
Database:
rank
-----
admin
PHP:
$rank =
Rank::from(
"admin"
);
Enum Methods
Enums can have methods.
Example:
enum Rank {
case OWNER;
case ADMIN;
case PLAYER;
public function color()
: string {
return match($this) {
self::OWNER =>
"gold",
self::ADMIN =>
"red",
self::PLAYER =>
"gray"
};
}
}
Usage:
echo
Rank::OWNER
->color();
Output:
gold
Match Expressions
Enums work perfectly with:
match()
Example:
$message =
match($rank) {
Rank::OWNER =>
"Owner",
Rank::ADMIN =>
"Admin",
Rank::PLAYER =>
"Player"
};
Enum Static Methods
Example:
enum Rank {
case OWNER;
case ADMIN;
public static function default()
: self {
return self::PLAYER;
}
}
Enum Interfaces
Enums can implement interfaces.
Example:
interface Colorable {
public function color()
: string;
}
Enum:
enum Rank
implements Colorable {
case OWNER;
case ADMIN;
public function color()
: string {
return "red";
}
}
Enum Traits
Enums can use traits.
Example:
trait LabelTrait {
public function label()
: string {
return ucfirst(
$this->name
);
}
}
Usage:
enum Rank {
use LabelTrait;
case OWNER;
case ADMIN;
}
Enum Properties?
Enums CANNOT contain properties.
Invalid:
enum Rank {
public string $name;
}
Error.
Why?
Enums are intended to be:
Immutable.
Enum Methods Available
PHP automatically provides:
name
Rank::OWNER->name
Output:
OWNER
value
For backed enums:
Rank::OWNER->value
Output:
owner
from()
Converts value to enum.
Example:
Rank::from(
"owner"
);
tryFrom()
Safer version.
Example:
Rank::tryFrom(
"invalid"
);
Output:
null
instead of exception.
Example
$rank =
Rank::tryFrom(
$databaseValue
);
if (
$rank === null
) {
}
cases()
Returns all enum cases.
Example:
Rank::cases();
Output:
[
Rank::OWNER,
Rank::ADMIN,
Rank::PLAYER
]
Usage
Creating dropdown menus.
Example:
foreach(
Rank::cases()
as $rank
)
{
echo
$rank->name;
}
Enterprise Examples
User Roles
enum UserRole {
case USER;
case MODERATOR;
case ADMIN;
case OWNER;
}
Order Status
enum OrderStatus {
case PENDING;
case PAID;
case CANCELLED;
case REFUNDED;
}
Payment Status
enum PaymentStatus {
case CREATED;
case PROCESSING;
case SUCCESS;
case FAILED;
}
API Example
enum ApiStatus
: int {
case SUCCESS = 200;
case ERROR = 500;
}
PocketMine Examples
Enums are extremely useful for:
Server State
enum ServerState {
case STARTING;
case RUNNING;
case STOPPING;
}
Player Rank
enum Rank {
case PLAYER;
case VIP;
case STAFF;
case ADMIN;
}
Game State
enum GameState {
case WAITING;
case STARTING;
case PLAYING;
case ENDING;
}
Arena State
enum ArenaStatus {
case CLOSED;
case OPEN;
case RESTARTING;
}
Packet Types
enum PacketType
: int {
case LOGIN = 1;
case CHAT = 2;
case MOVE = 3;
}
Why Enums are Amazing for Game Servers
Without enums:
if (
$state == "plaing"
)
Typo.
Bug.
With enums:
if (
$state ===
GameState::PLAYING
)
Perfectly safe.
Enums vs Constants
Constants
class Rank {
public const ADMIN =
"admin";
}
Problems:
❌ No type safety.
❌ Can pass invalid values.
Enums
Rank::ADMIN
Only valid values exist.
Comparison
| Feature | Constants | Enums |
|---|---|---|
| Type Safe | ❌ | ✅ |
| Methods | ❌ | ✅ |
| Cases() | ❌ | ✅ |
| Interfaces | ❌ | ✅ |
| Match Support | ❌ | ✅ |
Common Beginner Mistakes
Using Strings Everywhere
Bad:
$rank = "admin";
Using Integers
Bad:
$status = 4;
Nobody knows what 4 means.
Overusing Enums
Not everything needs enums.
Good Uses
✅ States
✅ Statuses
✅ Roles
✅ Permissions
✅ Packet Types
Bad Uses
❌ Usernames
❌ Dynamic values
❌ Database records
Best Practices
✅ Use enums for finite values.
✅ Prefer backed enums for databases.
✅ Add helper methods.
✅ Use match expressions.
Exercises
Exercise 1
Create:
enum Rank {
}
Cases:
OWNER
ADMIN
PLAYER
Exercise 2
Create:
enum GameState {
}