PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

PHP 8.1 preview – enums, readonly properties, intersection types, Fibers

by Henryk Tews / Tuesday, 09 November 2021 / Published in PHP

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.

About Henryk Tews

What you can read next

PHP 7.2 – object type hint, sodium instead of mcrypt, deprecations

© 2026 Created by

TOP
Zarządzaj zgodą
Aby zapewnić jak najlepsze wrażenia, korzystamy z technologii, takich jak pliki cookie, do przechowywania i/lub uzyskiwania dostępu do informacji o urządzeniu. Zgoda na te technologie pozwoli nam przetwarzać dane, takie jak zachowanie podczas przeglądania lub unikalne identyfikatory na tej stronie. Brak wyrażenia zgody lub wycofanie zgody może niekorzystnie wpłynąć na niektóre cechy i funkcje.
Funkcjonalne Always active
Przechowywanie lub dostęp do danych technicznych jest ściśle konieczny do uzasadnionego celu umożliwienia korzystania z konkretnej usługi wyraźnie żądanej przez subskrybenta lub użytkownika, lub wyłącznie w celu przeprowadzenia transmisji komunikatu przez sieć łączności elektronicznej.
Preferencje
Przechowywanie lub dostęp techniczny jest niezbędny do uzasadnionego celu przechowywania preferencji, o które nie prosi subskrybent lub użytkownik.
Statystyka
Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do celów statystycznych. Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do anonimowych celów statystycznych. Bez wezwania do sądu, dobrowolnego podporządkowania się dostawcy usług internetowych lub dodatkowych zapisów od strony trzeciej, informacje przechowywane lub pobierane wyłącznie w tym celu zwykle nie mogą być wykorzystywane do identyfikacji użytkownika.
Marketing
Przechowywanie lub dostęp techniczny jest wymagany do tworzenia profili użytkowników w celu wysyłania reklam lub śledzenia użytkownika na stronie internetowej lub na kilku stronach internetowych w podobnych celach marketingowych.
  • Manage options
  • Manage services
  • Manage {vendor_count} vendors
  • Read more about these purposes
Zobacz preferencje
  • {title}
  • {title}
  • {title}