PHP 8.1, uitgebracht op 25 november 2021 is eindelijk hier, boordevol verschillende opwindende features.

In dit artikel bespreken we in detail wat er nieuw is in PHP 8.1. Van de nieuwe features en prestatieverbeteringen tot belangrijke wijzigingen en afschrijvingen, we behandelen ze allemaal uitvoerig.

Let’s go!

Nieuwe features in PHP 8.1

Laten we beginnen met het behandelen van alle nieuwe features in PHP 8.1. En dat is nogal een lijst.

Pure intersection types

PHP 8.1 voegt ondersteuning toe voor intersection types. Deze zijn vergelijkbaar met union types die met PHP 8.0 hun intrede deden, maar waarvoor je ze kan gebruiken is precies het tegenovergestelde.

Om het gebruik ervan beter uit te leggen, is het goed om even kort te herhalen hoe type declarations werken in PHP.

In wezen kan je type declarations toevoegen aan function arguments, return values en class properties. Deze toewijzing wordt type hinting genoemd en zorgt ervoor dat de waarde van het juiste type is wanneer je deze callt. In andere gevallen geeft deze meteen een TypeError. Dit helpt je om je code beter de debuggen.

Het declaren van een enkel type heeft echter zijn beperkingen. Union types helpen je dit obstakel te overbruggen door je toe te staan een waarde met meerdere types te declaren, en de invoer moet ten minste voldoen aan één van de gedeclareerde types.

Het RFC beschrijft intersection types als volgt:

Een “intersection type” vereist een waarde om te voldoen aan meerdere type constraints in plaats van aan één.

…pure intersection types worden gespecificeerd met behulp van de syntaxis T1&T2&… en kunnen worden gebruikt in alle posities waar types momenteel worden geaccepteerd…

Let op het gebruik van de & (AND) operator om de intersection types te declareren. Daarentegen gebruiken we de | (OR) operator om union types te declaren.

Het gebruik van de meeste standaardtypes in een intersection type zal resulteren in een type waaraan nooit kan worden voldaan (bijv. integer en string). Daarom kunnen intersection types alleen class types bevatten (bijv. interfaces en class names).

Dit is voorbeeldcode van hoe je intersection types kan gebruiken:

class A {
    private Traversable&Countable $countableIterator;
 
    public function setIterator(Traversable&Countable $countableIterator): void {
        $this->countableIterator = $countableIterator;
    }
 
    public function getIterator(): Traversable&Countable {
        return $this->countableIterator;
    }
}

In de bovenstaande code hebben we een variabele countableIterator gedefinieerd als intersection van twee types: Traversable en Countable. In dit geval zijn de twee gedeclareerde types interfaces.

Intersection types voldoen ook aan de standaard PHP regels met betrekking tot variance die al worden gebruikt voor type checking en inheritance. Maar er zijn twee aanvullende regels met betrekking tot de interactie tussen intersection types en subtyping. Je kan in de RFC meer lezen over de variance regels rond intersection types.

In sommige programmeertalen kan je Union Types en Intersection Types combineren in dezelfde declaration. Maar PHP 8.1 verbiedt dit. Daarom wordt de implementatie ervan “pure” intersection types genoemd. De RFC vermeldt echter wel dat dit iets is waar ze in de toekomst nog naar willen kijken.

Enums

PHP 8.1 voegt eindelijk ondersteuning toe voor enums (ook wel enumerations of enumerated types genoemd). Ze zijn een user-defined data type dat bestaat uit een reeks mogelijke waarden.

De meest voorkomende voorbeelden van enums in programmeertalen is het boolean type met true en false als twee mogelijke waarden. Het is inmiddels zo gewoon dat het in veel moderne programmeertalen is ingebakken.

Volgens de RFC zijn enums in PHP in eerste instantie beperkt tot unit enumerations:

De scope van deze RFC is beperkt tot “unit enumerations”, dat wil zeggen enums die zelf een waarde zijn, in plaats van eenvoudigweg een fancy syntax voor een primitive constant, en die geen aanvullende bijbehorende informatie bevatten. Deze mogelijkheid biedt sterk uitgebreide ondersteuning voor gegevensmodellering, custom type definitions en monad-style behavior. Enums maken de modelleringstechniek mogelijk van “ongeldige toestanden onrepresenteerbaar maken”, wat leidt tot robuustere code met minder noodzaak aan veel testen.

Het PHP team heeft veel talen bestudeerd die al enumerations ondersteunen. Uit hun onderzoek bleek dat je enums in drie algemene groepen kunt indelen: Fancy Constants, Fancy Objects en volledige Algebraic Data Types (ADT’s). Het is interessant om te lezen!

PHP implementeert “Fancy Objects” enums, met plannen om het in de toekomst uit te breiden naar volledige ADT’s. Het is conceptueel en semantisch gemodelleerd naar de enumerated types in Swift, Rust en Kotlin, hoewel het niet direct op een van hen is gemodelleerd.

De RFC gebruikt de welbekende analogie van kleuren in een pak kaarten om uit te leggen hoe het zal werken:

enum Suit {
  case Hearts;
  case Diamonds;
  case Clubs;
  case Spades;
}

Hier definieert de enum Suit vier mogelijke waarden: Hearts, Diamonds, Clubs en Spades. Je kan deze waarden rechtstreeks benaderen met behulp van de syntax: Suit::Hearts, Suit::Diamonds, Suit::Clubs en Suit::Spades.

Dit gebruik lijkt misschien bekend, omdat enums bovenop classes en objects worden gebouwd. Ze gedragen op dezelfde manier en hebben bijna dezelfde vereisten. Enums delen dezelfde namespaces als classes, interfaces en traits.

De hierboven genoemde enums worden Pure Enums genoemd.

Je kan ook Backed Enums definiëren als je aan alle gevallen een scalar equivalent value wil geven aan cases. Backed enums kunnen echter maar één type hebben, ofwel int of string (nooit beide).

enum Suit: string {
  case Hearts = 'H';
  case Diamonds = 'D';
  case Clubs = 'C';
  case Spades = 'S';
}

Bovendien moeten alle verschillende cases van een backed enum een unieke waarde hebben. En je kan nooit pure en backed enums mengen.

De RFC gaat dieper in op enum methods, static methods, constants, constant expressions en nog veel meer. Het valt buiten de scope van dit artikel om ze allemaal te behandelen. Je kan de documentatie raadplegen om vertrouwd te raken met alles wat ermee te maken heeft.

Het never return type

PHP 8.1 voegt een nieuwe return type hint toe met de naam never. Deze is superhandig te gebruiken in functions die altijd throw of exit hebben.

Volgens de RFC zijn URL redirect functions die altijd exit (expliciet of impliciet) teruggeven, een goed voorbeeld van het gebruik ervan.

function redirect(string $uri): never {
    header('Location: ' . $uri);
    exit();
}
 
function redirectToLoginPage(): never {
    redirect('/login');
}

Een met never gedeclareerde function moet aan de volgende drie voorwaarden voldoen:

  • Het mag het return statement niet expliciet hebben gedefinieerd.
  • Het mag het return statement niet impliciet hebben gedefinieerd (bijv if-else statements).
  • Het moet de uitvoering beëindigen met een exit statement (expliciet of impliciet).

Het URL redirection voorbeeld hierboven laat zowel expliciet als impliciet gebruik van het never return type zien.

Het never return type heeft veel overeenkomsten met het void return type. Ze zorgen er allebei voor dat de function of method geen waarde teruggeeft. Het verschilt echter door strengere regels op te leggen. Een void gedeclareerde function kan nog steeds return zonder een expliciete waarde, maar hetzelfde geldt niet voor een never gedeclareerde function.

Als vuistregel: gebruik void wanneer je verwacht dat PHP blijft uitvoeren naar de function call. Kies voor never wanneer je het tegenovergestelde wilt.

Bovendien wordt never gedefinieerd als een “bottom” type. Daarom kan elke class method die als never wordt gedeclared nooit zijn return type in iets anders veranderen. Je kan echter een als void gedeclareerde method uitbreiden met een als never gedeclareerde method.

Fibers

Historisch gezien is PHP code bijna altijd synchrone code geweest. De uitvoering van de code stopt totdat het resultaat is geretourneerd, zelfs voor I/O operations. Je kan je voorstellen waarom dit proces de uitvoering van de code langzamer maakt.

Er zijn meerdere oplossingen van derden om dit obstakel te overwinnen, zodat developers PHP code asynchroon kunnen schrijven, met name voor gelijktijdige I/O bewerkingen. Sommige populaire voorbeelden zijn amphp, ReactPHP en Guzzle.

Er is echter geen standaardmanier om dergelijke instanties in PHP af te handelen. Bovendien leidt het behandelen van synchrone en asynchrone code binnen dezelfde call stack tot andere problemen.

Fibers zijn PHP’s manier om parallellisme af te handelen via virtuele threads (of groene threads). Het probeert het verschil tussen synchrone en asynchrone code te elimineren door PHP functions te onderbreken zonder de hele call stack te beïnvloeden.

Dit is wat de RFC belooft:

  • Ondersteuning voor Fibers toegevoegd aan PHP.
  • Introductie van een nieuwe Fiber class en de bijbehorende reflection class ReflectionFiber.
  • Het toevoegen van exception classes FiberError en FiberExit om fouten te representen.
  • Fibers zorgen voor transparante non-blocking I/O implementaties van bestaande interfaces (PSR-7, Doctrine ORM, etc.). Dat komt omdat het tijdelijke placeholder (promise) object wordt geëlimineerd. In plaats daarvan kunnen functions het I/O result type declaren in plaats van een placeholder object dat geen resolution type kan specificeren omdat PHP geen generics ondersteunt.

Je kan Fibers gebruiken om full-stack, interruptible PHP functions te ontwikkelen, die je vervolgens kan gebruiken om coöperatieve multitasking te implementeren in PHP. Omdat Fibers de hele execution stack pauzeren, kan je erop vertrouwen dat dit de rest van je code niet schaadt.

Grafiek die de executionflow van PHP code met Fibers illustreert
Grafiek die de executionflow van PHP code met Fibers illustreert (Bron: PHP.net).

Om het gebruik van Fibers te illustreren, gebruikt de RFC dit simpele voorbeeld:

$fiber = new Fiber(function (): void {
    $value = Fiber::suspend('fiber');
    echo "Value used to resume fiber: ", $value, "\n";
});
 
$value = $fiber->start();
 
echo "Value from fiber suspending: ", $value, "\n";
 
$fiber->resume('test');

In bovenstaande code maak je een “fiber” die je onmiddellijk suspendt met de string fiber. Het echo statement dient als een visuele cue voor de hervatting van de fiber.

Je kan deze string value uit de call ophalen naar $fiber->start().

Vervolgens hervat je de fiber met de string “test” die wordt geretourneerd door de call naar Fiber::suspend(). De volledige uitvoering van de code resulteert in de volgende output:

Value from fiber suspending: fiber
Value used to resume fiber: test

Dit is een simpel schoolvoorbeeld van de werking van PHP Fibers. Dit is nog een ander Fibers voorbeeld van het uitvoeren van zeven asynchrone GET verzoeken.

Dat gezegd hebbende, de meeste PHP developers zullen nooit rechtstreeks te maken krijgen met Fibers. Dit is ook wat de RFC suggereert:

Fibers zijn een geavanceerde features die de meeste gebruikers niet rechtstreeks zullen gebruiken. Deze feature is voornamelijk bedoeld voor auteurs van libraries and frameworks om een event loop en asynchrone programming API te bieden. Met Fibers kan je naadloos asynchrone code-uitvoering in synchrone code integreren zonder dat het nodig is om de call stack van de applicatie te wijzigen of boilerplate code te gebruiken.

De Fiber API zal naar verwachting niet rechtstreeks worden gebruikt in code op applicatieniveau. Met Fibers bieden we een simpele, low-level flow-control API om abstracties op hoger niveau te creëren die vervolgens worden gebruikt in applicatiecode.

Gezien de prestatievoordelen kan je verwachten dat vooral PHP libraries en frameworks profiteren van deze nieuwe feature. Het zal interessant zijn om te zien hoe ze Fibers in hun ecosysteem implementeren.

Nieuwe readonly properties

PHP 8.1 voegt ondersteuning toe voor readonly properties. Ze kunnen slechts een keer worden geïnitialiseerd vanuit de scope waarin ze zijn gedeclared. Zodra ze eenmaal geïnitialiseerd zijn, kan de waarde nooit meer gewijzigd worden. Als je dit toch doet, wordt een Error exception gegenereerd.

De RFC luidt:

Een readonly property kan slechts één keer worden geïnitialiseerd, en alleen vanuit de scope waarin het is gedeclared. Een andere assignment of wijziging van de property zal resulteren in een Error exception.

Hier volgt een voorbeeld van hoe je het kan gebruiken:

class Test {
    public readonly string $kinsta;
 
    public function __construct(string $kinsta) {
        // Legal initialization.
        $this->kinsta = $kinsta;
    }
}

Zodra hij geïnitialiseerd is, is er geen weg meer terug. Nu deze feature is ingebakken in PHP, wordt het gebruik aanzienlijk verminderd van boilerplate-code, die vaak wordt gebruikt om deze feature in te schakelen.

De readonly property biedt een sterke “onveranderlijkheidsgarantie”, zowel binnen als buiten de class. Het maakt niet uit welke code ertussen wordt uitgevoerd. Het callen van een readonly property zorgt altijd dat dezelfde waarde wordt geretourneerd.

Het gebruik van de readonly property is echter niet voor elke use-case ideaal. Je kan hem alleen gebruiken naast een typed property, omdat declarations zonder een type impliciet null zijn en niet readonly kunnen zijn.

Bovendien maakt het instellen van een readonly property objecten niet meteen onveranderlijk. De readonly property zal hetzelfde object bevatten, maar het object zelf kan natuurlijk wel veranderen.

Een ander klein probleem met deze property is dat je het niet kan klonen. Er is echter al een work-around voor deze specifieke use-case. Kijk er even naar als dit nodig is.

final class constants definiëren

Vanaf PHP 8.0 kun je class constants overschrijven met de bijbehorende child classes. Dit komt door de manier waarop inheritance werkt in PHP.

Hier is een voorbeeld van hoe je de waarde van een eerder gedeclareerde constant kan overschrijven:

class Moo
{
    public const M = "moo";
}
 
class Meow extends Moo
{
    public const M = "meow";
}  

Als de koeien strenger willen zijn met hoe de katten zich gedroegen (tenminste wat constants betreft), kunnen ze dat doen met de nieuwe final modifier van PHP 8.1.

Zodra je een constant declareert als final, dan betekent het simpel dat.

class Moo
{
    final public const M = "moo";
}
 
class Meow extends Moo
{
    public const M = "meow";
}
 
// Fatal error: Meow::M cannot override final constant Moo::M

Je kan meer lezen in de PHP RFC van de final class constants.

Nieuwe fsync() en fdatasync() functions

PHP 8.1 voegt twee nieuwe file system functions toe genaamd fsync() en fdatasync(). Ze zullen bekend voorkomen met mensen die gewend zijn aan Linux functions met dezelfde naam. Dat komt omdat ze gerelateerd zijn, maar in dit geval geïmplementeerd voor PHP.

Deze toevoeging heeft al lang op zich laten wachten. PHP is een van de weinige grote programmeertalen die fsync() en fdatasync nog steeds niet hebben geïmplementeerd – dat wil zeggen tot PHP 8.1.

De fsync() function is te vergelijken met de bestaande fflush() function, maar verschilt op één manier aanzienlijk. Waar fflush() de interne buffers van de applicatie naar de OS flusht, gaat fsync() nog een stapje verder en zorgt ervoor dat de interne buffers naar de fysieke opslag worden geflusht. Dat zorgt voor een volledige en persistente schrijfbewerking, zodat je zelfs na een applicatie- of systeemcrash gegevens kan retrieven.

Hier is een voorbeeld van hoe je het kunt gebruiken.

$doc = 'kinsta.txt';

$kin = fopen($doc, 'ki');
fwrite($kin, 'doc info');
fwrite($kin, "\r\n");
fwrite($kin, 'more info');

fsync($kin);
fclose($kin);

Het toevoegen van de fsync() call aan het einde zorgt ervoor dat alle gegevens die zich in de interne buffer van PHP of het besturingssysteem bevinden, naar de opslag worden geschreven. Alle andere code-uitvoeringen zijn tot die tijd geblokkeerd.

De gerelateerde function is fdatasync(). Gebruik deze om data te syncen, maar niet per se metadata. Voor data waarvan de metadata niet essentieel zijn, maakt deze function call het schrijfproces een beetje sneller.

Houd er echter rekening mee dat PHP 8.1 fdatasync() nog niet volledig ondersteunt op Windows. Het fungeert alleen als een alias van fsync(). Op POSIX is fdatasync() correct geïmplementeerd.

Nieuwe array_is_list() function

PHP arrays kunnen zowel integer als string keys bevatten. Dit betekent dat je ze voor verschillende dingen, waaronder lijsten, hashtabellen, woordenboeken, collecties, stacks, queues en nog veel meer. Je kan zelfs arrays binnen arrays hebben, waardoor multidimensionale arrays worden gemaakt.

Je kan efficiënt checken of een bepaald item een array is, maar het is niet zo eenvoudig om te controleren of het missende array offsets, out-of-order keys, enz. heeft. Kortom, je kan niet snel checken of een array een lijst is.

De array_is_list() function checkt of de keys van een array in sequentiële volgorde staan, beginnend bij 0 en zonder gaps. Als aan alle voorwaarden is voldaan, wordt true geretourneerd. Standaard retourneert het ook true voor lege arrays.

Hier zijn een paar voorbeelden van het gebruik ervan waarin zowel aan true als false voorwaarden wordt voldaan:

// true array_is_list() examples
array_is_list([]); // true
array_is_list([1, 2, 3]); // true
array_is_list(['cats', 2, 3]); // true
array_is_list(['cats', 'dogs']); // true
array_is_list([0 => 'cats', 'dogs']); // true
array_is_list([0 => 'cats', 1 => 'dogs']); // true 

// false array_is_list() examples 
array_is_list([1 => 'cats', 'dogs']); // as first key isn't 0
array_is_list([1 => 'cats', 0 => 'dogs']); // keys are out of order
array_is_list([0 => 'cats', 'bark' => 'dogs']); // non-integer keys
array_is_list([0 => 'cats', 2 => 'dogs']); // gap in between keys 

Een PHP array list met out-of-order keys is een potentiële bron van bugs. Het gebruik van deze function om een strikte naleving van list vereisten af te dwingen voordat verder wordt gegaan met het uitvoeren van de code, is een geweldige aanvulling op PHP.

Nieuwe Sodium XchaCha20 functions

Sodium is een moderne, gebruiksvriendelijke cryptografische bibliotheek voor encryptie, decryptie, hashing van wachtwoorden, handtekeningen en meer. De PECL libsodium package voegt een wrapper toe voor Sodium zodat PHP developers het kunnen gebruiken.

Zelfs toonaangevende technologiebedrijven als Facebook, Discord, Malwarebytes en Valve gebruiken libsodium om hun gebruikers te beveiligen met snelle en veilige verbindingen.

libsodium ondersteunt het XChaCha20 encryptie-algoritme om data te encrypten en decrypten, met name voor stream-encryptie. Daarnaast ondersteunt de PECL libsodium extensie XChaCha20 al0 al, maar alleen met Poly1305 bericht authenticatiecode.

Veel PHP applicaties gebruiken XChaCha20 rechtstreeks voor stream-encryptie. Om het je gemakkelijker te maken heb je vanaf PHP 8.1 drie nieuwe functions om data te encrypten of decrypten met XchaCha zonder dat er authenticatie nodig is. Deze modus wordt “detached mode” genoemd.

De nieuw geïntroduceerde XChaCha20 functions zijn:

  • sodium_crypto_stream_xchacha20_keygen: Retourneert een veilige willekeurige key voor gebruik met natrium_crypto_stream_xchacha20.
  • sodium_crypto_stream_xchacha20: Breidt de key en nonce uit tot een keystream van pseudo-willekeurige bytes.
  • sodium_crypto_stream_xchacha20_xor: versleutelt een bericht met een nonce en een secret key (geen authenticatie).

Daarnaast zijn er twee nieuwe PHP constants gedefinieerd in de globale namespace:

  • SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES (toegewezen 32)
  • SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES (toegewezen 24)

Gebruik het echter met de nodige voorzichtigheid. Omdat het zonder authenticatie is, is deze decoderingsbewerking kwetsbaar voor veelvoorkomende ciphertext aanvallen.

Je kan meer lezen over het gebruik en de vereisten op de Github pagina.

Nieuwe IntlDatePatternGenerator class

De onderliggende ICU library van PHP ondersteunt het maken van gelokaliseerde datum- en tijdnotaties, maar is niet volledig aanpasbaar.

Als je in versies tot PHP 8.0 bijvoorbeeld landspecifieke gegevens- en tijdnotaties wilt maken, kan je de vooraf gedefinieerde IntlDateFormatter constant gebruiken om dit op 6 manieren te doen:

  • IntlDateFormatter::LONG: langer, zoals November 10, 2017 of 11:22:33pm
  • IntlDateFormatter::MEDIUM: Iets korter, zoals November 10, 2017
  • IntlDateFormatter::SHORT: Alleen nummers zoals 10/11/17 of 11:22pm

Elk van deze heeft ook zijn eigen RELATIVE_ variants, die de datumnotatie binnen een beperkt bereik voor of na de huidige datum instellen. In PHP zijn de waarden yesterday, today en tomorrow.

Stel dat je de lange versie voor het jaar en de korte versie voor de maand wil gebruiken, zoals 10/11/2017. In PHP 8.0 en eerdere versies kan dit niet.

Vanaf PHP 8.1+ kan je opgeven welke indeling je wil gebruiken voor de datum, maand en tijd met de nieuwe class IntlDatePatternGenerator. De exacte volgorde van deze componenten kan je aan de formatter overlaten.

Houd er rekening mee dat hoewel deze class alleen het woord Date bevat, het consistent is met ICU’s DateTimePatternGenerator. Dit bekent dat je het ook kan gebruiken om flexibele tijdformats te maken. Om de naamgeving te vereenvoudigen, heeft het PHP team gekozen voor de kortere term IntlDatePatternGenerator.

Hier volgt een voorbeeld rechtstreeks uit de RFC:

$skeleton = "YYYYMMdd";
 
$today = \DateTimeImmutable::createFromFormat('Y-m-d', '2021-04-24');
 
$dtpg = new \IntlDatePatternGenerator("de_DE");
$pattern = $dtpg->getBestPattern($skeleton);
echo "de: ", \IntlDateFormatter::formatObject($today, $pattern, "de_DE"), "\n";
 
$dtpg = new \IntlDatePatternGenerator("en_US");
$pattern = $dtpg->getBestPattern($skeleton), "\n";
echo "en: ", \IntlDateFormatter::formatObject($today, $pattern, "en_US"), "\n";
 
/*
de: 24.04.2021
en: 04/24/2021
*/

In de bovenstaande code definieert de skeleton variabele de specifieke datum- of tijdnotaties die moeten worden gebruikt. De formatter handelt echter de volgorde van het eindresultaat af.

Ondersteuning voor de AVIF afbeeldingsindeling

AVIF, of AV1 Image File Format, is een relatief nieuw royaltyvrije afbeeldingsindeling op basis van de AV1 videocoderingsindeling. Naast het bieden van hogere compressie (en dus kleinere bestandsgroottes) ondersteunt het ook verschillende features als transparantie, HDR en meer.

De AVIF indeling was pas recentelijk gestandaardiseerd (8 juni 2021). Dit maakte de weg vrij voor browsers als Chrome 85+ en Firefox 86+ om ook AVIF afbeeldingen te ondersteunen.

PHP 8.1’s afbeeldingsverwerking en GD extensie voegt ondersteuning toe voor AVIF afbeeldingen.

Om deze functionaliteit op te nemen, moet je wel de GD extensie compileren met AVIF ondersteuning. Je kan dit doen door de onderstaande opdrachten uit te voeren.

Voor Debian/Ubuntu:

apt install libavif-dev

Voor Fedora/RHEL:

dnf install libavif-devel

Hiermee installeer je de nieuwste dependencies. Vervolgens kan je de AVIF ondersteuning compileren door de --with-avif flag te runnen met het ./configure script.

./buildconf --force
./configure --enable-gd --with-avif

Als je een volledig nieuwe omgeving aan het opbouwen bent, kan je hier ook andere PHP extensies inschakelen.

Eenmaal geïnstalleerd kan je testen of AVIF ondersteuning is ingeschakeld door de volgende opdracht in je PHP terminal uit te voeren:

php -i | grep AVIF

Als je AVIF correct hebt geïnstalleerd, zie je het volgende resultaat:

AVIF Support => enabled

Je kan ook de gd_info() call gebruiken om een lijst met GD features op te halen, inclusief of AVIF Support functionaliteit is ingeschakeld.

Deze bijgewerkte PHP 8.1 GD extensie voegt ook twee nieuwe functions toe voor het werken met AVIF afbeeldingen: imagecreatefromavif en imageavif. Ze werken op dezelfde manier als hun JPEG en PNG tegenhangers.

De imagecreatefromavif function retourneert een GdImage instance van een bepaalde AVIF afbeelding. Je kan deze instance vervolgens gebruiken om de afbeelding te bewerken of te converteren.

De andere imageavif function heeft als output het AVIF afbeeldingsbestand. Je kan het bijvoorbeeld gebruiken om een JPEG naar AVIF te converteren:

$image = imagecreatefromjpeg('image.jpeg');
imageavif($image, 'image.avif');

Je kan meer lezen over deze nieuwe feature op de GitHub pagina.

Nieuwe $_FILES full_path key voor directory uploads

PHP bevat een groot aantal vooraf gedefinieerde variabelen om verschillende dingen te tracken. Een daarvan is de $_FILES variabele die een associatieve array van items bevat die zijn geüpload via de HTTP POST methode.

De meeste moderne browsers ondersteunen het uploaden van een volledige map met HTML bestandsupload velden. Zelfs versies van voor PHP 8.1 ondersteunen deze functionaliteit, maar wel met een grote kanttekening. Je kan namelijk geen map uploaden met dezelfde mappenstructuur of relatieve paden, omdat PHP deze informatie niet doorgaf aan de $_FILES array.

Dit verandert in PHP 8.1 met de toevoeging van een nieuwe key genaamd full_path aan de $_FILES array. Met behulp van deze nieuwe data kan je nieuwe relatieve paden opslaan of de exacte directorystructuur op de server dupliceren.

Je kan deze informatie testen door de $FILES array te outputten met behulp van de opdracht var_dump($_FILES);.

Ga echter voorzichtig te werk als je deze nieuwe feature gebruikt. Zorg dat je beschermd bent tegen de standaard aanvallen bij het uploaden van bestanden.

Ondersteuning array unpacking voor string-keyed arrays

PHP 7.4 voegde ondersteuning toe voor array unpacking met de array spread operator (). Deze fungeert als een sneller alternatief dan wanner je de array_merge function gebruikt. Deze feature was echter beperkt tot numeric-keyed arrays omdat het unpacken van stringed-key arrays voor conflicten zorgde bij het mergen van arrays met dubbele keys.

PHP 8 voegde echter ondersteuning toe voor named arguments waardoor deze beperking is opgeheven. Daarom ondersteunt array unpacking nu ook string-keyed arrays met dezelfde syntax:

$array = [...$array1, ...$array2];

Dit RFC voorbeeld illustreert hoe het samenvoegen van arrays met dubele string keys wordt afgehandeld in PHP 8.1:

$array1 = ["a" => 1];
$array2 = ["a" => 2];
$array = ["a" => 0, ...$array1, ...$array2];
var_dump($array); // ["a" => 2]

Hier verschijnt de string key “a” driemaal voordat deze wordt gemerged via array unpacking. Maar alleen de laatste waarde die hoort bij $array2 wint.

Expliciete notatie van octale cijfers

PHP ondersteunt verschillende cijfersystemen, waaronder decimaal (base-10), binair (base-2), octaal (base-8) en hex (base-16). Het decimale cijfersysteem is de standaard.

Als je een ander cijfersysteem wil gebruiken, moet je een prefix toevoegen aan elk nummer met een standaard prefix:

  • Hex: 0x prefix. (e.g. 17 = 0x11)
  • Binary: 0b prefix. (e.g. 3 = 0b11)
  • Octal: 0 prefix. (e.g. 9 = 011)

Je kan zien hoe het prefix van het octale cijfersysteem verschilt van de rest. Om deze zorg te standaardiseren, voegen veel programmeertalen ondersteuning toe voor een expliciete octale cijfernotatie: 0o of 0O.

Beginnend met PHP 8.1 kan je het bovenstaande voorbeeld (d.w.z. nummer 9 in base-10) in het octale numerieke systeem schrijven als 0o11 of 0O11.

0o16 === 14; // true
0o123 === 83; // true
 
0O16 === 14; // true
0O123 === 83; // true
 
016 === 0o16; // true
016 === 0O16; // true

Bovendien werkt deze nieuwe feature ook met de underscore numeric literal separator die werd geïntroduceerd in PHP 7.4.

Lees meer over deze nieuwe PHP 8.1 feature in de RFC.

Ondersteuning MurmurHas3 en xxHash hash algoritmes

PHP 8.1 voegt ondersteuning toe voor MurmurHash3 en xxHash hashing algoritmes. Ze zijn niet bedoeld voor cryptografisch gebruik, maar ze bieden desalniettemin een indrukwekkende willekeur, spreiding en uniciteit van de output.

Deze nieuwe hashing algoritmes zijn sneller dan de meeste bestaande hashing algoritmes van PHP. Sommige varianten van deze hashing algoritmen zijn zelfs sneller dan de RAM throughput.

Omdat PHP 8.1 ook ondersteuning toevoegt voor het declaren van algoritme-specifieke $options parameters, kun je hetzelfde doen met deze nieuwe algoritmen. De standaardwaarde van dit nieuwe argument is []. Het heeft dus geen invloed op onze bestaande hash functions.

Je kan meer lezen over deze nieuwe PHP 8.1 features op hun GitHub pagina’s MurmurHash3xxHashAlgorithm-specific $options.

Ondersteuning DNS-over-HTTPS (DoH)

DNS-over-HTTPS (DoH) is een protocol voo DNS resolutie via het HTTPSprotocol. Door HTTPS te gebruiken om gegevens tussen de client en de DNS resolver te versleutelen, verhoogt DoH de privacy en veiligheid van gebruikers door MitM aanvallen te voorkomen.

Vanaf PHP 8.1 kan je de  Curl extensie gebruiken om een DoH server te specificeren. Het vereist dat PHP wordt gecompileerd met libcurl 7.62+ versies. Dit is geen probleem voor de meeste populaire besturingssystemen, inclusief Linux distro’s, omdat ze vaak al Curl 7.68+ bevatten.

Je kan de DoH server URL configureren door de CURLOPT_DOH_URL option op te geven.

$doh = curl_init('https://kinsta.com');
curl_setopt($doh, CURLOPT_DOH_URL, 'https://dns.google/dns-query');
curl_exec($doh);

In het bovenstaande voorbeeld hebben we de openbare DNS server van Google gebruikt. Let ook het gebruik van https:// in alle URL’s die je gebruikt. Zorg dat je dit perfect configureert omdat er geen standaard DNS server is om op terug te vallen in Curl.

Je kan ook kiezen uit een lijst met openbare DoH servers die je in de Curl documentatie kan vinden.

Bovendien legt de CURLOPT_DOH_URL reference van de documentatie van Curl uit hoe je de verschillende arguments kan gebruiken.

Bestandsuploads van strings met CURLStringFile

De PHP Curl extensie ondersteunt HTTP(S) verzoeken bij bestandsuploads. Het gebruik de CURLFile class om dit te bereiken, die een URI of een bestandspad, een mime type en de uiteindelijke bestandsnaam accepteert.

Met de CURLFile class kan je echter alleen het bestandspad of URI accepteren, maar niet de inhoud van het bestand zelf. In scenario’s waar je het bestand al moest uploaden naar het geheugen (bijv. verwerkte afbeeldingen, XML documenten, PDF’s) dan moest je data:// URI’s gebruiken met Base64 encoding.

Maar libcurl ondersteunt al een veel makkelijkere manier om de inhoud van het bestand te accepteren. De nieuwe CURLStringFile class voegt die ondersteuning dus toe.

Je kan de GitHub pagina lezen om meer te leren over hoe het is geïmplementeerd in PHP 8.1.

Nieuwe MYSQLI_REFRESH_REPLICA constant

PHP 8.1’s mysqli extensie voegt een nieuwe constant toe genaamd MYSQLI_REFRESH_REPLICA. Het is vergelijkbaar met de al bestaande MYSQLI_REFRESH_SLAVE constant.

Deze wijziging was welkom in MySQL 8.0.23 om raciaal getinte termen te adresseren in tech vocabulaire (met als meest bekende voorbeeld “slave” en “master”).

Merk wel op dat de oudere constant niet verwijderd of afgeschreven is. Developers en applicaties kunnen het blijven gebruiken. De nieuwe constant is eigenlijk niets meer dan een optie voor developers en bedrijven om deze terminologie niet te gebruiken.

Prestatieverbeteringen met Inheritance Cache

Inheritance Cache is een nieuwe toevoeging voor opcache die de overhead van PHP class inheritance elimineert.

PHP classes worden afzonderlijk door opcache gecompileerd en gecachet. Ze worden echter in run-time aan elkaar gelinkt bij elk verzoek. Dit proces kan een paar compabiliteitschecks omvatten, plus het lenen van methods/properties/constants van parent classes en traits.

Als gevolg kan het nogal wat tijd kosten om het uit te voeren, ook al is het resultaat van elk verzoek hetzelfde.

Inheritance Cache linkt alle unieke dependent classes (parent, interfaces, traits, property types, methods) en slaat de resultaten op in het gedeelde geheugen van opcache. Omdat dit nu maar één keer gebeurt, kost inheritance minder nu instructies.

Bovendien verwijdert dit beperkingen voor immutable classes, zoals unresolved constants, typed properties en covariant type checks. Daarom zijn alle classes die zijn opgeslagen in opcache immutable, wat het aantal vereiste instructies nog meer vermindert.

Al met al belooft het belangrijke prestatieverbeteringen. Dimitry Stogov, de auteur van deze patch, heeft laten zien dat het 8% verbeteringen brengt op het base Symfony programma “Hello, World!”. We kunnen niet wachten om het uit te testen in de PHP benchmarks.

First-class callable syntax

PHP 8.1 voegt een first-class callable syntax toe om bestaande encodings met strings en arrays te vervangen. Naast het creëren van een strakkere Closure is deze nieuwe syntax ook toegankelijk is voor statische analysetools en respecteert het de gedeclarede scope.

Hier zijn een paar voorbeelden uit de RFC:

$fn = Closure::fromCallable('strlen');
$fn = strlen(...);
 
$fn = Closure::fromCallable([$this, 'method']);
$fn = $this->method(...)
 
$fn = Closure::fromCallable([Foo::class, 'method']);
$fn = Foo::method(...);

Hier zijn alle expression pairs equivalenten. De triple-dot () syntax is vergelijkbaar met de argument-unpacking syntax (...$args). Maar in dit geval zijn de arguments nog niet ingevuld.

Wijzigingen in PHP 8.1

PHP 8.1 bevat ook wijzigingen aan de bestaande syntax en features. Laten we ze behandelen:

PHP interactive shell vereist readline extensie

PHP’s readline extensie schakeld interactive shell features in zoals navigatie, autocompletion, bewerken en meer. Hoewel het is gebundeld met PHP, is het niet standaard ingeschakeld.

Je krijgt toegang tot de interactive shell van PHP door gebruik te maken van PHP CLI’s -a command-line optie:

php -a

Interactive shell

php >
php > echo "Hello";
Hello
php > function test() {
php { echo "Hello";
php { }
php > test();
Hello

Vóór PHP 8.1 kon je zelfs met PHP CLI de interactive shell openen zonder dat de readline extensie was ingeschakeld. Zoals verwacht werkten de interactive features van de shell niet, wat de -a optie zinloos maakte.

In PHP 8.1 CLI, maakt de interactive shell een exit met een foutbericht als je de readline extensie niet ingeschakeld hebt.

php -a
Interactive shell (-a) requires the readline extension.

MySQLi standaard error mode ingesteld op exceptions

Vóór PHP 8.1 was het de standaard in MySQLi om de errors als silent te beschouwen. Dit gedrag zorgde vaak voor code die niet de strikte Error/Exception handling volgde. Developers moesten hun eigen expliciete error handling functions implementeren.

PHP 8.1 verandert dit gedrag door de standaard modus van MySQLi’s om errors te reporten te veranderen in het geven van een exception.

Fatal error: Uncaught mysqli_sql_exception: Connection refused in ...:...

Aangezien dit een belangrijke wijziging is, moet je voor PHP <8.1 versies expliciet de error handling mode instellen met de function mysqli_report voordat je de eerste MySQLi verbinding maakt. Je kan hetzelfde bereiken door de error reporting waarde te selecteren door een mysqli_driver instance te instantiëren.

De RFC volgt een vergelijkbare wijziging die werd geïntroduceerd in PHP 8.0.

Aanpasbare line endings voor CSV writing functions

Vóór PHP 8.1 waren de ingebouwde CSV writing functions van PHP, fputcsv and SplFileObject::fputcsv, hard-coded om \n (of het Line-Feed teken) toe te voegen aan het einde van elke regel.

PHP 8.1 voegt ondersteuning toe aan deze functions voor een nieuwe parameter genaamd eol. Je kan het gebruiken om een configureerbaar end-of-line teken door te geven. Standaard gebruikt het nog steeds het \n teken. Je kan het dus blijven gebruiken in je bestaande code.

Standaard character escaping regels zijn van toepassing voor het gebruik van end-of-line karakters. Als je \r, \n of \r\n als EOL tekens wilt gebruiken, moet je deze tussen dubbele aanhalingstekens plaatsen.

Hier is de GitHub pagina die deze nieuwe wijziging trackt.

Nieuwe beperkingen version_compare operator

PHP’s version_compare() vergelijkt twee versienummer strings. Deze function accepteert een derde optionele argument genaamd operator om te testen op een bepaalde relatie.

Hoewel dit niet expliciet in de documentatie wordt behandeld, kon je deze parameter instellen open een gedeeltelijke waarde (bijv. g, l, n) zonder dat dit een error opleverde.

PHP 8.1 voegt strengere beperkingen toe aan de version_compare() function’s operator argument om deze situatie te verhelpen. De enige operators die je nu kan gebruiken zijn:

  • ==, =, en eq
  • !=, <>, en ne
  • > en gt
  • >= en ge
  • < en lt
  • <= en le

Geen gedeeltelijke operatorwaarden meer.

HTML encoding en decoding functions gebruiken nu ENT_QUOTES | ENT_SUBSTITUTE

HTML entities zijn tekstuele representaties van tekens die anders als HTML zouden worden geïnterpreteerd. Denk aan tekens als < en > die worden gebruikt om HTML tags te definiëren (bijv. <a>, <h3>, <script>).

De HTML entity voor < is < (kleiner dan symbool) en > is > (groter dan symbool). Je kan deze HTML entities veilig gebruiken binnen een HTML document zonder dat je de rendering engine van de browser triggert.

Je zal bijvoorbeeld in de browser <script> als <script> zien, in plaats van dat het wordt geïnterpreteerd als HTML tag.

Vóór PHP 8.1 converteerden de htmlspecialchars() en htmlentities() functions symbolen als <>, en & naar hun respectievelijke HTML entities. Maar ze converteerden niet standaard het enkele aanhalingsteken () naar de HTML entity. Bovendien gaven ze een lege string terug als er een misvormde UTF-8 in de tekst stond.

In PHP 8.1. zullen deze HTML encoding en decoding functions (en hun gerelateerde functions) ook standaard enkele aanhalingstekens naar hun HTML entity converteren.

En als de gegeven tekst ongeldige tekens bevat, zullen de functions deze vervangen door een Unicode vervangingsteken (�) in plaats van een lege string terug te geven. PHP 8.1 doet dit door de signatures van deze functions standaard te wijzigen in ENT_QUOTES | ENT_SUBSTITUTE in plaats van ENT_COMPAT .

De meeste frameworks gebruiken ENT_QUOTES als de standaard flag waarde. Je zal dus niet zo heel veel verschil zien door deze wijziging. De nieuwe ENT_SUBSTITUTE flag wordt echter niet zo veel gebruikt. PHP 8.1 zorgt ervoor dat ongeldige UTF-8 tekens worden vervangen door het � teken in plaats van een lege string terug te geven.

Waarschuwing voor illegale compact function calls

PHP’s compact() function is superhandig. Je kan hem gebruiken om een array met variabelen te maken met hun namen en waarden.

Bekijk de volgende code:

$animal = 'Cat';
$sound = 'Meow';
$region = 'Istanbul';
compact('animal', 'sound', 'region');
// ['animal' => "Cat", 'sound' => "Meow", 'region' => "Istanbul"]

De documentatie van de compact function vermeldt dat het alleen string parameters of array waarden met string waarden accepteert. Vóór PHP 7.3 zouden alle strings die niet zijn ingesteld silent worden overgeslagen.

PHP 7.3 heeft de compact() function aangepast om een melding weer te geven als je ongedefinieerde variabelen gebruikt. PHP 8.1 gaat nog een stap verder en geeft een waarschuwing.

Je kunt de GitHub pagina lezen om te begrijpen hoe deze verandering tot stand kwam.

Nieuwe migraties van resources naar class objects

Een van de langetermijndoelen van PHP is om weg te gaan van resources naar standard class objects.

Om historische redenen worden resource objects veel gebruikt in PHP applicaties. Daarom moet de migratie van resources naar class objects zo min mogelijk verstorend werken. PHP 8.1 migreert vijf van dergelijke resources:

The file_info resource migreert naar finfo objects

PHP’s finfo class biedt een object-oriented interface voor de fileinfo functions. Het gebruik van finfo functions retourneert echter resource objects met het file_info type in plaats van een instance met de finfo class zelf.

PHP 8.1 lost deze anomalie op.

IMAP resources migreren naar IMAP\Connection class objects

In lijn met het doel van de resource-naar-object migratie, minimaliseert de nieuwe IMAP\Connection class  wijzigingen wanneer PHP uiteindelijk de implementatiedetails van de class wijzigt.

Deze nieuwe class wordt ook gedeclared als final, wat een extend onmogelijk maakt.

Lees meer over de implementatie ervan op de GitHub pagina.

FTP connection resources zijn nu FTP\Connection class objects

Als je in PHP <8.1 een FTP verbinding maakte met de ftp_connect of ftp_ssl_connect() functions, dan kreeg je een resource object terug van het ftp type.

PHP 8.1 voegt de nieuwe FTP/Connection class toe om dat recht te zetten. En net als bij de IMAP\Connection class, wordt ook deze als final gedeclared zodat het niet kan worden extend.

Lees meer over de implementatie op de GitHub pagina.

Font identifiers migreren naar GdFont class objects

PHP’s GD extensie heeft de imageloadfont() function om een user-defined bitmap te loaden en de resource ID van de font-identifier terug te geven (een integer).

In PHP 8.1 zal deze function echter in plaats daaran een GdFont class instance teruggeven. Om de migratie probleemloos te laten verlopen, zullen alle functions die voorheen een resource ID van imageloadfont() accepteerden, nu de nieuwe GdFont class objects gebruiken.

Lees meer over deze migratie in de GitHub pagina.

LDAP resources migreren naar objects

LDAP or Lightweight Directory Access Protocol wordt gebruikt om toegang te krijgen tot “Directory Servers”. Net als een directory structuur van een harde schijf is het een unieke database die gegevens bevat in een boomstructuur.

PHP bevatte vóór PHP 8.1 een LDAP extensie die resource objects accepteerde of teruggaf. Ze zijn nu echter allemaal naadloos gemigreerd naar nieuwe class instances. De resource types die zijn overgezet zijn:

  • ldap link resource naar \LDAP\Connection class object
  • ldap result resource naar \LDAP\Result class object
  • ldap result entry resource naar \LDAP\ResultEntry class object

Blader vooral door de GitHub pagina om deze migratie beter te begrijpen.

Pspell resources zijn nu class objects

Met de Pspell extensie van PHP kan je spelling en woordsuggesties checken.

PHP <8.1 gebruikte psell en pspell config resources object types met een integer identifier. Deze twee resource objects worden nu vervangen door PSpell\Dictionary en PSpell\Config class objects.

Net als bij eerdere migraties zullen alle Pspell functions die voorheen resource object identifiers accepteerden of teruggaven de nieuwe class object instances gebruiken.

Raadpleeg de GitHub pagina voor meer informatie.

Afschrijvingen in PHP 8.1

PHP 8.1 deprecieert veel van zijn vorige features. De volgende lijst geeft een kort overzicht van de functionaliteiten die PHP 8.1 afschrijft:

Kan null niet doorgeven aan non-nullable internal function paramters

In PHP 8.0 accepteren de internal functions (silent) null waarden, zelfs voor non-nullable arguments. Hetzelfde geldt niet voor user-defined functions – deze accepteren alleen null voor nullable arguments.

Kijk bijvoorbeeld eens naar het volgende gebruik:

var_dump(str_contains("foobar", null));
// bool(true)

Hier wordt de null waarde (silent) geconverteerd naar een lege string. Het resultaat retourneert dus true.

Deze RFC is bedoeld om het gedrag van internal functions te synchroniseren door in PHP 8.1 een deprecation waarschuwing te geven.

var_dump(str_contains("foobar", null));
// Deprecated: Passing null to argument of type string is deprecated

Deze afschrijving wordt een TypeError in de volgende grote PHP versie (bijv. PHP >=9.0), waardoor het gedrag van internal functions consistent is met user-defined functions.

Beperkt gebruik $GLOBALS

PHP’s $GLOBALS variabele biedt een directe verwijzing naar zijn interne symbooltabel. Het ondersteunen van deze functionaliteit is complex en beïnvloedt de prestatie van array operations. Bovendien werd er zelden gebruik van gemaakt.

Volgens de RFC is het indirect wijzigen van $GLOBALS niet langer toegestaan. Deze wijziging is achterwaarts incompatibel.

De impact van deze wijziging is relatief laag:

In de top 2k composer packages vond ik 23 gevallen die $GLOBALS gebruiken zonder er rechtstreeks naar te verwijzen. Op basis van een vluchtige inspectie zijn er slechts twee instances waar $GLOBALS niet wordt gebruikt op een read-only manier.

Read-only gebruik van $GLOBALS blijft echter gewoon werken. Wat niet langer wordt ondersteund is het schrijven naar $GLOBALS als geheel. Als gevolg hiervan kan je een lichte prestatiebump verwachten, helemaal als je met gewone PHP arrays werkt.

Return type declarations voor internal functions

PHP 8.0 stond developers toe om parameters en return types te declaren voor de meeste interne functions en methods. Dit was mogelijk dankzij verschillende RFC’s, zoals Consistent type errors voor internal functions, Union Types 2.0 en Mixed Type v2.

Er zijn echter veel gevallen waarin type informatie kan ontbreken. Sommigen van hen bevatten een type met resources, out pass-by-ref parameters, return type van non-final methods en functions of methods die volgens de algemene regels geen parameters parsen. Je kan de precieze details lezen in de de RFC.

Deze RFC lost alleen het probleem op met het return type van non-final methods. Maar in plaats van het echter onmiddellijk volledig uit te faseren, biedt het PHP team een geleidelijke migratie zodat je je codebase kan bijwerken met de relevante method return types.

Non final internal method return types – indien mogelijk – worden voorlopig gedeclareerd in PHP 8.1 en zullen worden afgedwongen in PHP 9.0. Dit betekent dat je in PHP 8.x versies een “deprecated” melding krijgt tijdens inheritance checks wanneer een internal method op zo’n manier wordt overschreven dat de return types incompatibel zijn. In PHP 9.0 krijg je een fatal error.

Als je deze deprecation melding krijgt na het updaten naar PHP 8.1, zorg er dan voor dat je de return types van je methods bijwerkt.

Serializable interface afgeschreven

PHP 7.4 introduceerde het custom object serialization mechanisme met twee nieuwe magic methods: __seralize() en __unserialize(). Deze nieuwe methods zijn bedoeld om de niet functionerende Serializable interface uiteindelijk te vervangen.

Deze RFC stelt voor om die beslissing af te ronden door een plan op te stellen voor de uiteindelijke verwijdering van Serializable.

Als je in PHP 8.1 de Seriazable interface implementeert zonder __serialize() en __unserialize methods te implementeren, dan geeft PHP je een “Deprecated” waarschuwing.

Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in ... on line ...

Als je PHP <7.4 en PHP >=7.4 ondersteunt, dan moet je zowel de Serializable als de nieuwe magic methods implementeren. Bij PHP >=7.4 versies, hebben de magic methods voorrang.

Niet-compatibele float naar int conversies afgeschreven

PHP is een dynamisch getypte taal. Als zodanig zijn er veel gevallen waarin type coercion van nature voorkomt. De meeste van de coercions zijn ongevaarlijk en eigenlijk superhandig.

Wanneer een float nummer echter wordt geconverteerd naar een integer, gaat dit echter vaak gepaard met gegevensverlies. Wanneer de float 3.14 bijvoorbeeld wordt geconverteerd naar een integer 3, dan verliest het zijn fractionele waarde.

Hetzelfde gebeurt wanneer de float buiten het platform integer bereik valt, of wanneer een float string wordt geconverteerd naar een integer.

PHP 8.1 corrigeert dit gedrag en brengt de dynamische type coercing meer in overeenstemming met de meeste moderne programmeertalen. Het doel is om dergelijke coercions voorspelbaar en intuïtief te maken.

In PHP 8.1 zie je een deprecation melding wanneer impliciete coercion optreedt van niet-compatibele float naar een int. Maar wat is een integer-compatible float? De RFC antwoordt hierop:

Van een float wordt gezegd dat hij integer-compatible is als hij de volgende kenmerken bezit:

  • Is een getal (dus niet NaN of Infinity)
  • Ligt binnen het bereik van een PHP integer (platformafhankelijk)
  • Heeft geen fractioneel deel

Deze deprecation melding zal worden geüpgraded naar een TypeError in de volgende grote PHP-versie (dwz PHP 9.0).

De mysqli::get_client_info Method en mysqli_get_client_info($param) afgeschreven

De MySQL client API definieert twee constants: client_info (een string) en client_version (een int). MySQL Native Driver (MySQLnd) maakt deel uit van de officiële PHP source koppelt deze constants aan de PHP versie. In libmysql vertegenwoordigen ze de versie van de client library op het moment van compilatie.

Vóór PHP 8.1  exposede mysqli deze constants op 4 manieren: mysqli_driver properties, mysqli propertiesmysqli_get_client_info() function, en mysqli::get_client_info method. Er is echter geen method voor client_version.

MySQLnd exposet deze constants op 2 manieren aan PHP: een constant en een function call. Om mysqli acces methods te verenigen met dezelfde twee options, schrijft PHP 8.1 deze twee options af:

  • get_client_info method in de mysqli class. In plaats daarvan kan je simpelweg de function mysqli_get_client_info() gebruiken.
  • mysqli_get_client_info() function met parameters. Call de function met elke parameter om de deprecation melding te vermijden.

Lees meer over deze afschrijving op de GitHub pagina.

Alle mhash*() functions (hash extensie) zijn afgeschreven

PHP 5.3 integreerde mhash*() functions in ext/hash als een compatibility layer voor ext/mhash. Later werd deze ext/mhash verwijderd in PHP 7.0.

In tegenstelling tot de hash_*() functions, zijn de mhash*() functions niet altijd beschikbaar. Je moet ze afzonderlijk inschakelen tijdens het configureren van PHP.

In PHP 7.4 was de hash extensie samen met PHP gebundeld, wat het tot een standaard extensie voor PHP maakt. Het ondersteunde echter om compatibiliteitsredenen nog wel het inschakelen van de --enable-mhash optie.

Het PHP heeft besloten om mhash*() functions af te schrijven in pHP 8.1 en ze in PHP 9.0 helemaal te verwijderen. De af te schrijven functions zijn mhash()mhash_keygen_s2k()mhash_count()mhash_get_block_size() en mhash_get_hash_name(). Je kan in plaats daarvan de standaard ext/hash functionaliteit gebruiken.

Zowel filter.default als filter.default_options INI instellingen afgeschreven

Met PHP’s filter.default INI instellingen kan je een filter toepassen op alle PHP super-globals — dwz GPCRS data ($_GET$_POST$_COOKIE$_REQUEST, en $_SERVER).

Je kan bijvoorbeeld filter.default=magic_quotes of filter.default=add_slashes instellen  (gebaseerd op de PHP versie) om PHP’s controversiële en onveilige magic quotes feature nieuw leven in te blazen (verwijderd in PHP 5.4).

De filter.default INI instelling biedt extra functionaliteit door veel meer filters toe te staan, wat het alleen maar erger maakt. De another option – filter.default=special_chars – maakt bijvoorbeeld magic quotes alleen voor HTML mogelijk. Er is veel minder bekendheid met deze instellingen.

PHP 8.1 geeft een deprecation melding als filter.default is ingesteld op een andere waarde dan unsafe_raw (de standaardwaarde). Je ziet geen aparte deprecation melding voor filter.default_options, maar PHP 9.0 zal deze beide INI instellingen verwijderen.

Als alternatief kan je de function filter_var() gaan gebruiken. Het filtert variabelen met het opgegeven filter.

autovivification bij false afgeschreven

PHP maakt autovivification mogelijk (automatische creatie van arrays van false waarden). Deze feature is superhandig als de variabele niet is gedefinieerd.

Desalniettemin is het niet ideaal om automatisch een array te maken wanneer de waarde false of null is.

Deze RFC verbiedt autovivification van false waarden. Merk echter op dat autovivification van ongedefinieerde variabelen en null nog steeds is toegestaan.

In PHP 8.1 zal het appenden aan een variabele van het type false een deprecation melding geven:

Deprecated: Automatic conversion of false to array is deprecated in

PHP 9.0 zal een fatal error laten zien voor hetzelfde, die identiek is aan andere scalar types.

De mysqli_driver->driver_version property wordt afgeschreven

De mysqli_driver->driver_version property van MySQLi’s extensie is al 13 jaar niet bijgewerkt. Ondanks vele wijzigingen die sindsdien aan de driver zijn gemaakt, geeft het nog steeds de waarde van de versie van de oude driver, wat deze property zinloos maakt.

In PHP 8.1 wordt de mysqli_driver->driver_version property afgeschreven.

Overige kleine wijzigingen

Er zijn veel meer deprecations in PHP 8.1. Het wordt te veel om ze allemaal in dit artikel te benoemen. We raden aan om rechtstreeks de RFC te lezen voor deze kleine afschrijvingen.

PHP’s GitHub pagina bevat ook een PHP 8.1 UPGRADE NOTES gids. Het geeft een overzicht van alle belangrijke wijzigingen die je moet overwegen voordat je een upgrade naar PHP 8.1 uitvoert.

Samenvatting

PHP 8.1 is beter dan zijn voorganger, wat geen geringe prestatie is. We denken dat de meest spannende PHP 8.1 features Enums, Fibers, Pure Intersection Types en de vele prestatieverbeteringen zijn. We kunnen dan ook niet wachten om PHP 8.1 op de proef te stellen en verschillende PHP frameworks en CMS’en te benchmarken.

Zorg ervoor dat je dit blogartikel opslaat in je favorieten als toekomstig naslagwerk.

Welke PHP 8.1 feature is jouw favoriet? Deel je mening met de community in de reacties hieronder.

Salman Ravoof

Salman Ravoof is a self-taught web developer, writer, creator, and a huge admirer of Free and Open Source Software (FOSS). Besides tech, he's excited by science, philosophy, photography, arts, cats, and food. Learn more about him on his website, and connect with Salman on Twitter.