PHP 8.1: Enums, Readonly Properties en Fibers
PHP 8.1 verscheen op 25 november 2021 en is achteraf een van de belangrijkste releases van het afgelopen decennium. Enums, readonly properties en fibers veranderden hoe moderne PHP-code eruitziet, en vrijwel elk framework leunt er inmiddels op. Tegelijk is PHP 8.1 sinds 31 december 2025 end of life: er komen geen securityfixes meer. In dit artikel kijken we wat 8.1 bracht, hoe je de features goed gebruikt, en waarom je er niet op moet blijven hangen.
Enums: types in plaats van magische strings
Voor 8.1 werden statussen en categorieën meestal opgeslagen als klasseconstanten of losse strings. Niets hield je tegen om 'gepubliceerd' te schrijven waar 'published' verwacht werd. Enums maken van zo'n waarde een eigen type.
Pure enums
enum Status
{
case Concept;
case Gepubliceerd;
case Gearchiveerd;
}
function publiceer(Artikel $artikel, Status $status): void
{
// $status kan alleen een van de drie cases zijn
}
publiceer($artikel, Status::Gepubliceerd);
Een enum-case is een object en een singleton: Status::Concept === Status::Concept is altijd true. Je kunt er geen new op doen en ze hebben geen state.
Backed enums
Wil je de waarde opslaan in een database of versturen in JSON, dan geef je elke case een scalaire waarde, een string of een int:
enum Status: string
{
case Concept = 'concept';
case Gepubliceerd = 'gepubliceerd';
case Gearchiveerd = 'gearchiveerd';
public function label(): string
{
return match ($this) {
self::Concept => 'Concept',
self::Gepubliceerd => 'Online',
self::Gearchiveerd => 'Gearchiveerd',
};
}
public function isZichtbaar(): bool
{
return $this === self::Gepubliceerd;
}
}
$status = Status::from('gepubliceerd'); // Status::Gepubliceerd
$onbekend = Status::tryFrom('verwijderd'); // null
echo $status->value; // gepubliceerd
echo $status->label(); // Online
from() gooit een ValueError bij een onbekende waarde, tryFrom() geeft null. Gebruik from() waar een onbekende waarde een bug is, en tryFrom() bij invoer van buiten.
Enums kunnen methoden, constanten en interfaces hebben, en met Status::cases() krijg je alle cases als array. Laravel en Doctrine kunnen backed enums direct casten van en naar databasekolommen, zodat je in je models nooit meer met losse strings werkt:
// Laravel
protected function casts(): array
{
return ['status' => Status::class];
}
De volledige uitleg, inclusief statische methoden en constanten in enums, staat in onze documentatie over basis-enumeraties en backed enumerations.
Readonly properties: onveranderlijk zonder boilerplate
Een readonly property kan precies één keer een waarde krijgen, en alleen vanuit de klasse zelf. Daarna is hij onveranderlijk. Gecombineerd met constructor promotion uit PHP 8.0 levert dat compacte, betrouwbare data-objecten op:
final class Adres
{
public function __construct(
public readonly string $straat,
public readonly string $postcode,
public readonly string $plaats,
) {}
}
$adres = new Adres('Dorpsstraat 1', '3441 AA', 'Woerden');
$adres->plaats = 'Utrecht'; // Error: Cannot modify readonly property
Een paar regels om te kennen:
- Readonly werkt alleen op getypeerde properties, en een readonly property kan geen standaardwaarde hebben.
- Readonly is ondiep. Bevat de property een object, dan kun je de eigenschappen van dat object nog steeds aanpassen. Alleen de verwijzing zelf is bevroren.
- Een "gewijzigde kopie" maak je met een methode die een nieuw object teruggeeft, het zogenaamde wither-patroon:
$adres->metPlaats('Utrecht').
Latere versies bouwden hierop voort. PHP 8.2 introduceerde readonly class, waarmee alle properties in één keer readonly worden. PHP 8.3 maakte het mogelijk readonly properties opnieuw te initialiseren binnen __clone(), wat deep cloning van immutable objecten eindelijk netjes oplost.
Fibers: de basis onder asynchrone PHP
Fibers zijn het minst zichtbare, maar technisch meest ingrijpende onderdeel van 8.1. Een fiber is een functie die halverwege kan pauzeren en later verder kan gaan, met zijn eigen call stack:
$fiber = new Fiber(function (string $begin): string {
$tweede = Fiber::suspend("{$begin} -> gepauzeerd");
return "hervat met: {$tweede}";
});
$tussenstand = $fiber->start('gestart');
echo $tussenstand; // gestart -> gepauzeerd
$fiber->resume('nieuwe data');
echo $fiber->getReturn(); // hervat met: nieuwe data
Het belangrijke verschil met generators: een fiber kan pauzeren vanuit diep in een aanroepketen, zonder dat elke functie daartussen een generator hoeft te zijn. Daardoor kan een library asynchrone I/O doen terwijl jouw code eruitziet als gewone, synchrone PHP.
Je schrijft zelden zelf fibers. Ze zijn bedoeld voor asynchrone libraries: AMPHP v3 bouwt op de event loop Revolt, en ReactPHP gebruikt ze in zijn async-component. Ook in tools die veel HTTP-requests parallel uitvoeren, zoals crawlers of API-integraties, kom je ze onder de motorkap tegen. Lees meer in onze documentatie over fibers.
Wat 8.1 nog meer bracht
- First-class callable syntax:
strlen(...)of$this->verwerk(...)maakt eenClosurevan een functie of methode, zonder strings of arrays als callable. newin initializers:public function __construct(private Logger $logger = new NullLogger()) {}.- Pure intersection types:
Countable&Traversableals parametertype. - Het returntype
nevervoor functies die altijd een exceptie gooien of het script beëindigen. array_is_list()om te controleren of een array opeenvolgende numerieke sleutels vanaf 0 heeft.finalklasseconstanten en de expliciete octaalnotatie0o16.
PHP 8.1 is end of life: wat nu?
PHP-versies krijgen twee jaar actieve support en daarna nog twee jaar securityfixes. Voor 8.1 is dat laatste jaar op 31 december 2025 afgelopen. Draait jouw applicatie nog op 8.1 of ouder, dan worden nieuw ontdekte kwetsbaarheden niet meer gedicht. Dat is niet alleen een technisch risico: bij een datalek telt het ook mee in de vraag of je "passende maatregelen" hebt genomen onder de AVG.
Het goede nieuws: de stap van 8.1 naar 8.3 of 8.4 is veel kleiner dan de sprong van PHP 7 naar 8. De meeste breaking changes zijn deprecations die je met PHPStan en Rector grotendeels automatisch kunt oplossen. Op de pagina PHP-versies zie je per versie tot wanneer hij ondersteund wordt, en in PHP-migratie lees je hoe een versie-upgrade in de praktijk verloopt.
Ben je al op 8.4? Dan zijn property hooks de logische volgende stap na readonly properties.