PHP 8.1 is due in November 2021 and brings the most significant type system additions since PHP 7.0. Enums solve a problem we have been working around with class constants for years. Readonly properties close the final gap in immutable value objects. Intersection types complete the union types from PHP 8.0. Fibers introduce cooperative multitasking. I go through each with practical examples.
Enums – first-class enumerated types
<?php
declare(strict_types=1);
// Pure enum - no backing value, just names
enum Status
{
case Active;
case Inactive;
case Pending;
}
// Backed enum - each case has a value (string or int)
enum OrderStatus: string
{
case Pending = 'pending';
case Processing = 'processing';
case Complete = 'complete';
case Cancelled = 'cancelled';
// Enums can have methods
public function label(): string
{
return match($this) {
self::Pending => 'Awaiting payment',
self::Processing => 'In progress',
self::Complete => 'Completed',
self::Cancelled => 'Cancelled',
};
}
public function isFinal(): bool
{
return in_array($this, [self::Complete, self::Cancelled]);
}
}
// Usage
$status = OrderStatus::Processing;
echo $status->value; // 'processing'
echo $status->name; // 'Processing'
echo $status->label(); // 'In progress'
// Create from value (e.g. from database)
$fromDb = OrderStatus::from('complete'); // OrderStatus::Complete
$safe = OrderStatus::tryFrom('invalid'); // null instead of exception
// Type hint - can only pass a valid OrderStatus
function canCancel(OrderStatus $status): bool
{
return !$status->isFinal();
}
echo canCancel(OrderStatus::Pending) ? 'Yes' : 'No'; // Yes
echo canCancel(OrderStatus::Complete) ? 'Yes' : 'No'; // No
Enums implement interfaces
<?php
interface HasColour
{
public function colour(): string;
}
enum Priority: int implements HasColour
{
case Low = 1;
case Medium = 2;
case High = 3;
case Urgent = 4;
public function colour(): string
{
return match($this) {
self::Low => '#28a745',
self::Medium => '#ffc107',
self::High => '#fd7e14',
self::Urgent => '#dc3545',
};
}
}
// List all cases
$cases = Priority::cases(); // [Priority::Low, Priority::Medium, ...]
Readonly properties
<?php
declare(strict_types=1);
class Money
{
// Can only be assigned once - in the constructor
public function __construct(
public readonly int $amount, // in pence
public readonly string $currency,
) {}
public function add(Money $other): static
{
if ($this->currency !== $other->currency) {
throw new \InvalidArgumentException('Currency mismatch');
}
return new static($this->amount + $other->amount, $this->currency);
}
public function format(): string
{
return number_format($this->amount / 100, 2) . ' ' . $this->currency;
}
}
$price = new Money(9999, 'PLN'); // 99.99 PLN
$shipping = new Money(1499, 'PLN'); // 14.99 PLN
$total = $price->add($shipping);
echo $total->format(); // 114.98 PLN
// Attempt to modify - fatal error
// $price->amount = 1000; // Error: Cannot modify readonly property
Intersection types
<?php
interface Countable
{
public function count(): int;
}
interface Iterable
{
public function toArray(): array;
}
// Intersection type: must implement BOTH interfaces
function processCollection(Countable&Iterable $collection): void
{
echo "Count: " . $collection->count() . PHP_EOL;
foreach ($collection->toArray() as $item) {
echo $item . PHP_EOL;
}
}
Fibers – cooperative multitasking
<?php
// Fiber - a lightweight coroutine that can be suspended and resumed
$fiber = new Fiber(function(): string {
echo "Fiber: started\n";
$received = Fiber::suspend('first suspension'); // pause, pass value to caller
echo "Fiber: resumed, got: {$received}\n";
return 'fiber result';
});
$value1 = $fiber->start(); // run until first suspend()
echo "Main: fiber suspended with: {$value1}\n";
$fiber->resume('hello from main'); // resume with a value
echo "Fiber returned: " . $fiber->getReturn() . "\n";
// Output:
// Fiber: started
// Main: fiber suspended with: first suspension
// Fiber: resumed, got: hello from main
// Fiber returned: fiber result
Summary
PHP 8.1 is the most impactful minor release in recent memory. Enums replace the class-constants antipattern with a type-safe, IDE-friendly alternative. Readonly properties make immutable value objects clean and concise – no more private properties with only a getter. Intersection types round out the type system. Fibers are the foundation for async PHP in libraries like ReactPHP and Amp.
