Veel RFC’s zijn al goedgekeurd en geïmplementeerd, dus is het hoog tijd om eens goed te kijken naar de meest interessante toevoegingen die PHP sneller en betrouwbaarder zouden moeten maken.

Omdat PHP 8 nog in ontwikkeling is, is het mogelijk dat er voor de definitieve release nog enkele wijzigingen optreden. We houden deze bij en zullen dit artikel regelmatig bijwerken, zodat je niets mist over PHP 8. Check dit artikel een keer in de zoveel tijd dus gerust opnieuw.

Dus, welke functies en verbeteringen kunnen we verwachten met PHP 8? Wat is het belangrijkste van PHP 8, de volgende grote release van deze scripttaal?

Tijd om verder te kijken!

PHP JIT (Just in Time Compiler)

De feature van PHP 8 waar de meeste mensen naar uitkijken is de Just-in-Time (JIT) compiler. Maar wat is JIT precies?

Het RFC voorstel beschrijft JIT als volgt:

“PHP JIT is geïmplementeerd als een zo goed als onafhankelijk onderdeel van OPcache. Het kan voor de compileertijd en voor de looptijd van PHP worden ingeschakeld/uitschakeld. Wanneer het is ingeschakeld, wordt de native code van PHP data in een extra regio van OPcache Shared Memory opgeslagen en zorgen op_array→opcodes[].handler(s) voor verwijzigen naar de toegangspunten van ge-JIT-eerde code.”

Maar hoe zijn we bij JIT aanbeland en wat is het verschil tussen JIT en OPcache?

Laten we, om de rol van JIT binnen PHP beter te begrijpen, eens kijken hoe PHP zaken uitvoert: vanaf de broncode tot het uiteindelijke resultaat.

De PHP uitvoering is een proces in 4 fasen:

De volgende afbeelding toont een visuele weergave van het standaard PHP uitvoerproces.

Standaard PHP uitvoeringsproces

Standaard PHP uitvoeringsproces

Maar hoe maakt OPcache PHP nu sneller? En wat verandert er met JIT precies aan dit uitvoeringsproces?

De OPcache extensie

PHP is een geïnterpreteerde taal. Dit betekent dat, wanneer een PHP script wordt uitgevoerd, de interpreter deze parsed (ontleedt), compileert en uitvoert. Dit gebeurt bij elk nieuw verzoek opnieuw en opnieuw. Het nadeel hiervan laat zich raden: de kans is groot dat je hierdoor tijd en CPU resources verspilt.

Dit is waar de OPcache extensie van pas komt:

“Opcache verbetert de prestaties van PHP door een voorgecompileerde script-bytecode in het Shared Memory op te slaan. Hierdoor vervalt voor PHP de noodzaak om bij elk verzoek scripts te laden en te parsen.”

Wanneer OPcache is ingeschakeld, hoeft de PHP interpreter alleen bij de eerste keer dat het script wordt uitgevoerd, de 4 stappen die we hierboven noemden te doorlopen. Omdat PHP bytecodes in het Shared Memory worden opgeslagen, zijn ze meteen beschikbaar als een low-level intermediate representation en kunnen ze meteen op de Zend VM worden uitgevoerd.

Het PHP uitvoeringsproces met OPcache ingeschakeld

Het PHP uitvoeringsproces met OPcache ingeschakeld

Vanaf PHP 5.5 is de Zend OPcache extensie standaard beschikbaar. Je kan makkelijk controleren of je deze correct hebt geconfigureerd door phpinfo() aan te roepen vanuit een script op je server of door je php.ini bestand te checken (zie OPcache configuratie-instellingen).

Zend Opcache sectie in een phpinfo pagina

Zend Opcache sectie in een phpinfo() pagina

Preloading

OPcache is onlangs verbeterd met de toevoeging van preloading, een nieuwe OPcache function die is toegevoegd in PHP 7.4. Preloading biedt een manier om een opgegeven set scripts op te slaan in het OPcache geheugen “voordat welke applicatiecode dan ook wordt uitgevoerd“, maar brengt geen significante verbeteringen voor typische webgebaseerde applicaties.

Je kan meer lezen over preloading in onze inleiding tot PHP 7.4.

Met JIT zet PHP een stap vooruit..

JIT — The Just in Time Compiler

Zelfs als opcodes de vorm hebben van intermediate representations, moeten ze nog steeds worden gecompileerd in machinecode. JIT “introduceert geen aanvullend IR (Intermediate Representation) formulier”, maar gebruikt DynASM (Dynamic Assembler voor codegeneratie-engines) om uit PHP byte-code rechtstreeks native code te genereren.

Kortom, JIT vertaalt de “hete delen” van de intermediate code in machinecode. Door het compilatieproces over te slaan, zou het aanzienlijke verbeteringen in prestaties en geheugenverbruik kunnen betekenen.

Zeev Surasky, co-auteur van het PHP JIT voorstel, laat hoeveel sneller berekeningen zouden zijn met JIT:

Maar zou JIT ook de WordPress prestaties effectief kunnen verbeteren?

JIT voor Live Web Apps

Volgens de JIT RFC zou de implementatie van de Just-in-Time Compiler de prestaties van PHP moeten verbeteren. Maar zouden we dergelijke verbeteringen ook daadwerkelijk ervaren binnen real-life apps als WordPress?

De eerste tests tonen inderdaad aan dat JIT CPU intensieve workloads aanzienlijk versnelt, maar de RFC waarschuwt:

“… net als de vorige pogingen – het lijkt er momenteel niet op dat het significante verbeteringen brengt aan real-life apps als WordPress (met opcache.jit=1235 326 req/sec vs 315 req/sec).

Het is de bedoeling dat we hiermee nog verder aan de slag gaan, om JIT te verbeteren voor real-life apps met behulp van profiling en speculatieve optimalisaties.”

Wanneer JIT is ingeschakeld, wordt de code niet uitgevoerd door Zend VM, maar door de CPU zelf. Dit zou de berekeningssnelheid moeten verbeteren. Web apps als WordPress zijn ook afhankelijk van andere factoren als TTFB, database-optimalisatie, HTTP verzoeken, etc.

Dus als het gaat om WordPress en vergelijkbare apps, mogen we eigenlijk geen flinke boost verwachten in de uitvoeringssnelheid van PHP. Toch kan JIT, met name voor ontwikkelaars, verschillende voordelen met zich meebrengen.

Volgens Nikita Popov:

“De voordelen van de JIT Compiler zijn grofweg (en zoals al beschreven in de RFC):

  • Significant betere prestaties voor numerieke code.
  • Iets betere prestaties voor “typische” PHP webapplicatiecode.
  • De potentie om meer code van C naar PHP te verplaatsen, omdat PHP nu snel genoeg zal zijn.”

Dus hoewel JIT nauwelijks noemenswaardige verbeteringen zal brengen wat betreft WordPress prestaties, tilt het wel PHP naar het volgende niveau, waarmee het een taal wordt waar veel functions nu rechtstreeks in kunnen worden geschreven.

Het nadeel is wel dat de grotere complexiteit kan leiden tot hogere kosten voor onderhoud, stabiliteit en debugging. Volgens Mitry Stogov:

“JIT is uiterst eenvoudig, maar het verhoogt wel het complexiteitsniveau van PHP als geheel, met een verhoogd risico op nieuwe soorten bugs en een hogere kosten voor ontwikkeling en onderhoud.”

Het voorstel om JIT op te nemen in PHP 8 werd aangenomen met 50 stemmen voor en 2 stemmen tegen.

PHP 8 doet later dit jaar zijn intrede. 🚀 Lees onze gedetailleerde beschrijving van alle nieuwe features!Click to Tweet

Verbeteringen en nieuwe functions PHP 8

Naast JIT kunnen we veel andere functions en verbeteringen verwachten met PHP 8. De volgende lijst is een zorgvuldig samengestelde selectie van de aankomende toevoegingen en wijzigingen die PHP betrouwbaarder en efficiënter moeten gaan maken.

Constructor Property Promotion

Als gevolg van een voortdurende discussie over hoe we object ergonomics in PHP kunnen verbeteren, stelt de Constructor Property Promotion RFC een nieuwe en beknoptere syntax voor die de property declaration simplificeert, waardoor deze korter en zinvoller wordt.

Dit voorstel heeft alleen betrekking op promoted parameters, dwz de method parameters met de visibility keywords public, protected en private als prefix.

Momenteel moeten alle property’s meerdere keren herhaald worden (minimaal vier keer) voordat we ze met objects kunnen gebruiken. Kijk eens naar het volgende voorbeeld uit de RFC:

class Point {
    public int $x;
    public int $y;
    public int $z;

    public function __construct(
        int $x = 0,
        int $y = 0,
        int $z = 0,
    ) {
        $this->x = $x;
        $this->y = $y;
        $this->z = $z;
    }
}

Volgens Nikita Popov, de bedenker van de RFC, moeten we de property name minstens vier keer op drie verschillende plaatsen neerzetten: de property declaration, de constructor parameters en de property assignment. Deze syntax is niet erg bruikbaar, vooral niet in classes met een groot aantal property’s en meer beschrijvende namen.

Deze RFC stelt voor om de constructor en de parameter definition samen te voegen. Vanaf PHP 8 gaan we dus beschikken we dus over een meer bruikbare manier om parameters te declareren en kan je de bovenstaande code veranderen in wat je hieronder ziet:

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}

En dat was het al. We hebben dus de beschikking over een nieuwe manier om property’s te promoten: korter, beter leesbaar en minder foutgevoelig. Volgens Nikita:

Het is een kleine syntactische transformatie die we hier voorstellen. Maar het vermindert wel de hoeveelheid code die je moet schrijven voor met name value objects…

De property declaration wordt getransformeerd aangezien we deze property’s al expliciet hebben gedeclared. We kunnen de Reflection API gebruiken om de property definitions vóór de uitvoering te introspecten (zie Sesugaring):

Reflection (en andere andere introspectionmechanismen) observeren de state na desugaring. Dit betekent dat de promoted property’s er hetzelfde uitzien als expliciet gedeclarede property’s en promoted constructor arguments verschijnen dus als ordinary constructor arguments.

// before desugaring
class Point {
    public function __construct(public int $x = 0) {}
}

// after desugaring
class Point {
    public int $x;

    public function __construct(int $x = 0) {
        $this->x = $x;
    }
}

Inheritance

We hebben geen beperkingen opgesteld bij het gebruik van inheritance in combinatie met promoted parameters. Hoe dan ook, er is specifieke relatie tussen constructors van parent en child class. Volgens Nikita:

Meestal zeggen we dat methoden altijd compatibel moeten zijn met de bovenliggende methode. […] maar deze regel is niet van toepassing op de constructor. De constructor behoort dus echt tot een single class en constructors tussen parent en child class hoeven op geen enkele manier compatibel te zijn.

Dit is een voorbeeld:

class Test {
    public function __construct(
        public int $x = 0
    ) {}
}

class Child extends Test {
    public function __construct(
        $x, 
        public int $y = 0,
        public int $z = 0,
    ) {
        parent::__construct($x);
    }
}

Wat niet toegestaan is bij promoted property’s

Promoted property’s zijn toegestaand in non-abstract constructors en traits, maar er zijn een aantal beperkingen die het vermelden waard zijn.

Abstract constructors

Promoted property’s zijn niet toegestaan in abstract classes en interfaces:

abstract class Test {
    // Error: Abstract constructor.
    abstract public function __construct(private $x);
}
 
interface Test {
    // Error: Abstract constructor.
    public function __construct(private $x);
}
Nullability

Een van de meest opvallende beperkingen houdt verband met nullability. Eerder, wanneer we een type gebruikten dat niet expliciet nullabel was, maar die wel een null als default value had, dan was het type impliciet nullabel. Maar met property types hebben we dit impliciete gedrag niet, omdat promoted parameters een property declaration vereisen. Het nullable type moet dus expliciet gedeclared worden. Bekijk het onderstaande voorbeeld van de RFC:

class Test {
    // Error: Using null default on non-nullable property
    public function __construct(public Type $prop = null) {}

    // Correct: Make the type explicitly nullable instead
    public function __construct(public ?Type $prop = null) {}
}
Callable Type

Aangezien “callable” geen property type is dat wordt ondersteund, mogen we geen callable type gebruiken in promoted property’s:

class Test {
    // Error: Callable type not supported for properties.
    public function __construct(public callable $callback) {}
}
The var Keyword Is Not Allowed

Alleen een visibility keyword kan worden gebruikt met promoted parameters, dus het declaren van constructor property’s met het var keyword is niet toegestaan (zie het onderstaande voorbeeld van de RFC):

class Test {
    // Error: "var" keyword is not supported.
    public function __construct(var $prop) {}
}
No Duplications Allowed

We kunnen promoted property’s en explicit property’s combineren binnen dezelfde class, maar property’s kunnen niet twee keer worden gedeclared:

class Test {
    public string $prop;
    public int $explicitProp;

    // Correct
    public function __construct(public int $promotedProp, int $arg) {
        $this->explicitProp = $arg;
    }

    // Error: Redeclaration of property.
    public function __construct(public string $prop) {}
}
Variadic Parameters Are Not Allowed

De reden is dat het declared type verschilt van de variadic parameters, wat eigenlijk een array is:

class Test {
    // Error: Variadic parameter.
    public function __construct(public string ...$strings) {}
}

Verder lezen

Als je meer wil weten over Constructor Property Promoted, luister dan naar dit interview met Nikita Popov. Voor een uitgebreid overzicht van object ergonomics in PHP, zie dit artikel en het volgende interview met Larry Garfield.

Validatie voor abstract trait methods

Traits worden gedefinieerd als “een mechanisme voor hergebruik van code in single-inheritance talen als PHP”. Normaal gesproken worden ze gebruikt om methods vast te leggen die in meerdere classes kunnen worden gebruikt.

Een trait kan ook abstract methods bevatten. Deze methods leggen alleen de signature van de method vast, de implementatie van de method moet binnen de class worden gedaan met behulp van de trait.

Volgens de PHP handleiding,

“Traits ondersteunen het gebruik van abstract methods om eisen te stellen aan de exhibiting class.”

Dit betekent ook dat de signatures van de methods overeen moeten komen. Met andere woorden, het type en het aantal vereiste arguments moeten hetzelfde zijn.

Hoe dan ook, volgens de auteur van de RFC, Nikita Popov, wordt de signature-validatie momenteel alleen sporadisch afgedwongen:

Het volgende voorbeeld van Nikia heeft betrekking op het eerste geval (de niet-afgedwongen signature):

trait T {
	abstract public function test(int $x);
}
 
class C {
	use T;

	// Allowed, but shouldn't be due to invalid type.
	public function test(string $x) {}
}

Dat gezegd hebbende, deze RFC stelt voor om altijd een fatal error te geven wanneer de implementing method niet compatibel is met de abstract trait method, ongeacht de oorsprong:

Fatal error: Declaration of C::test(string $x) must be compatible with T::test(int $x) in /path/to/your/test.php on line 10

Deze RFC is unaniem goedgekeurd.

Incompatibele method signatures

In PHP veroorzaken inheritance errors als gevolg van incompatibele method signatures een fatal error of een waarschuwing, afhankelijk van wat de fout veroorzaakt.

Als een class een interface implementeert, dan veroorzaken incompatibele method signatures een fatal error. Volgens de Oject Interfaces documentatie:

“De class die de interface implementeert moet een method signature gebruiken die compatibel is met LSP (Liskov Substitution Principle). Als je dit niet doet, krijg je een fatal error.”

Dit is een voorbeeld van een inheritance error met een interface:

interface I {
	public function method(array $a);
}
class C implements I {
	public function method(int $a) {}
}

In PHP 7.4 zou de bovenstaande code de volgende error opleveren:

Fatal error: Declaration of C::method(int $a) must be compatible with I::method(array $a) in /path/to/your/test.php on line 7

Een function in een child class met een incompatible signature zou een error geven. Bekijk de volgende code van de RFC:

class C1 {
	public function method(array $a) {}
}
class C2 extends C1 {
	public function method(int $a) {}
}

In PHP 7.4 zou de bovenstaande code alleen een waarschuwing geven:

Warning: Declaration of C2::method(int $a) should be compatible with C1::method(array $a) in /path/to/your/test.php on line 7

Deze RFC gaat een stapje verder en stelt voor om een fatal error te genereren voor incompatibele method signatures. Met PHP 8 zou de code die we eerder zagen het volgende oproepen:

Fatal error: Declaration of C2::method(int $a) must be compatible with C1::method(array $a) in /path/to/your/test.php on line 7

Arrays beginnend met een negatieve index

Als een array in PHP begint met een negatieve index (start_index <0), dan beginnen de indices erna vanaf 0 (meer hierover in array_fill documentatie). Dit wordt toegelicht in het volgende voorbeeld:

$a = array_fill(-5, 4, true);
var_dump($a);

In PHP 7.4 zou dit resulteren in het volgende:

array(4) {
	[-5]=>
	bool(true)
	[0]=>
	bool(true)
	[1]=>
	bool(true)
	[2]=>
	bool(true)
}

Deze RFC stelt hierin een wijziging voor, zodat de tweede index start_index +1 zou zijn, ongeacht de value van start_index.

In PHP zou bovenstaande code dus resulteren in de volgende array:

array(4) {
	[-5]=>
	bool(true)
	[-4]=>
	bool(true)
	[-3]=>
	bool(true)
	[-2]=>
	bool(true)
}

Met PHP vertonen arrays die beginnen met een negatieve index dus ander gedrag. Lees meer over backward incompatibilities in de RFC zelf.

Union types 2.0

Untion types accepteren values die van verschillende types kunnen zijn. Momenteel biedt PHP geen ondersteuning voor union types, met uitzondering van de ?Type syntax en special type iterable.

Voor PHP 8 konden union types alleen worden gespecificeerd in phpdoc annotations, zoals je kan zien in het onderstaande voorbeeld van de RFC:

class Number {
	/**
	 * @var int|float $number
	 */
	private $number;

	/**
	 * @param int|float $number
	 */
	public function setNumber($number) {
		$this->number = $number;
	}

	/**
	 * @return int|float
	 */
	public function getNumber() {
		return $this->number;
	}
}

De RFC Union Types 2.0 stelt voor om ondersteuning voor union types toe te voegen in function signatures, zodat we niet meer afhankelijk zijn van inline documentatie, maar nu union types kunnen definiëren met een T1|T2|… syntax:

class Number {
	private int|float $number;

	public function setNumber(int|float $number): void {
		$this->number = $number;
	}

	public function getNumber(): int|float {
		return $this->number;
	}
}

Dit wordt uitgelegd door Nikita Popov in de RFC,

“Door in de taal union types te ondersteunen kunnen we meer type information verplaatsen van phpdoc naar function signatures, met de gebruikelijke voordelen die dit met zich meebrengt:

Union types ondersteunen alle beschikbare types, met enkele beperkingen:

Je kan in het RFC meer lezen over Union Types V2..

Consistent type errors voor internal functions

Wanneer een parameter van een illegaal type wordt doorgegeven, gedragen internal en user-define functions zich anders.

User-defined functions veroorzaken een TypeError, maar internal functions gedragen zich op verschillende manieren, afhankelijk van verschillende voorwaarden. Hoe dan ook, het typische antwoord is om een waarschuwing te geven en een null te retourneren. Zie het onderstaande voorbeeld in PHP 7.4:

var_dump(strlen(new stdClass));

Dit zou de volgende waarschuwing opgeven:

Warning: strlen() expects parameter 1 to be string, object given in /path/to/your/test.php on line 4
NULL

Als strict_types is ingeschakeld of argument information types specificeert, dan zien we ander gedrag. In dergelijke scenario’s wordt de type error gedetecteerd en resulteert het in een TypeError.

Deze situatie zou leiden tot een aantal problemen. Dit wordt uitvoerig uitgelegd in de Issues sectie van de RFC.

Om deze inconsistenties te verwijderen, stelt deze RFC voor om de internal parameter die API’s parseert altijd een ThrowError te laten genereren in het geval een parameter type niet overeenkomt.

Fatal error: Uncaught TypeError: strlen(): Argument #1 ($str) must be of type string, object given in /path/to/your/test.php:4

Fatal error: Uncaught TypeError: strlen(): Argument #1 ($str) must be of type string, object given in /path/to/your/test.php:4
Stack trace:
#0 {main}
  thrown in /path/to/your/test.php on line 4

throw Expression

In PHP is throw een statement. Het is dus niet mogelijk om deze te gebruiken op plekken waar alleen een expression is toegestaan.

Deze RFC stelt voor om het throw statement om te zetten in een expression zodat deze ook kan worden gebruikt in context waarin expressions zijn toegestaan. Denk hierbij aan arrow functions, null coalesce operator, ternary en elvis operators, etc.

Bekijk de volgende voorbeelden van de RFC:

$callable = fn() => throw new Exception();

// $value is non-nullable.
$value = $nullableValue ?? throw new InvalidArgumentException();
 
// $value is truthy.
$value = $falsableValue ?: throw new InvalidArgumentException();

Weak Maps

Een weak map is een collectie van data (objects) waarin keys weakly referenced zijn. Dit voorkomt dat ze garbaged collected worden.

Heb je razendsnelle, veilige en ontwikkelaars-vriendelijke hosting nodig voor de sites van je klanten? Kinsta is gebouwd met WordPress developers in het achterhoofd en biedt een breed scala aan tools en een krachtig dashboard. Check onze pakketten

PHP 7.4 voegde ondersteuning toe voor weak references als een manier om een reference naar een object te behouden, maar dat niet verhindert dat het object zelf wordt vernietigd. Zoals Nikita Popov opmerkte,

“Raw weak references zijn op zichzelf van beperkt nut en weak maps worden in de praktijk veel vaker gebruikt. Het is niet mogelijk om een efficiënte weak map bovenop PHP weak references te implementeren, omdat de mogelijkheid om een destruction callback te registreren niet wordt geboden.”

Dat is waarom deze RFC een WeakMap class introduceert om objects te maken die kunnen worden gebruikt als weak map keys. Deze kunnen worden vernietigd en verwijderd van de weak map als er geen verdere verwijzingen zijn naar het key object.

In langlopende processen zou dit memory leaks kunnen voorkomen en prestaties kunnen verbeteren. Bekijk het onderstaande voorbeeld van de RFC:

$map = new WeakMap;
$obj = new stdClass;
$map[$obj] = 42;
var_dump($map);

Met PHP zou de bovenstaande code het volgende resultaat opleveren (zie de code hier in actie):

object(WeakMap)#1 (1) {
	[0]=>
	array(2) {
		["key"]=>
		object(stdClass)#2 (0) {
		}
		["value"]=>
		int(42)
	}
}

Als je het object unset, wordt de key automatisch uit de weak map verwijderd:

unset($obj);
var_dump($map);

Nu zou het resultaat het volgende zijn:

object(WeakMap)#1 (0) {
}

Voor meer informatie over Weak Maps kan je het best de RFC lezen. Het voorstel was unaniem goedgekeurd.

Trailing comma in parameter list

Trailing commas zijn komma’s die zijn toegevoegd aan lijsten met items in verschillende contexten. PHP 7.2 introduceerde trailing commas in list syntax en PHP 7.3 introduceerde trailing commas in function calls.

PHP introduceert nu trailing commas in parameter lists met functions, methods en closures. In onderstaand voorbeeld kan je meer zien:

class Foo {
	public function __construct(
		string $x,
		int $y,
		float $z, // trailing comma
	) {
		// do something
	}
}

Het voorstel werd aangenomen met 58 tegen 1 stemmen.

::class toegestaan voor objects

Om de naam van een class te fetchen, kan je de syntax Foo\Bar::class gebruiken. Deze RFC stelt voor om dezelfde syntax uit te breiden naar objects. Hierdoor is het nu mogelijk om de naam van de class van een bepaald object op te halen, zoals je in onderstaand voorbeeld kan zien:

$object = new stdClass;
var_dump($object::class); // "stdClass"
 
$object = null;
var_dump($object::class); // TypeError

Met PHP 8 geeft $object:class hetzelfde resultaat als get_class($object). Als $object geen object is, genereert het een TypeError exception.

Dit voorstel was unaniem goedgekeurd.

Attributes v2

Attributes, ook al bekend als annotations, zijn een vorm van structured metadata die kunnen worden gebruikt om properties te specificeren voor objects, elements of files.

Tot PHP 7.4 waren doc-comments de enige manier om metadata toe te voegen aan declarations van classes, functions, etc. De Attributes v2 RFC introduceert attributes voor PHP die ze definiëren als een vorm van structured, syntactic metadata die kunnen worden toegevoegd aan declarations van classes, properties, functions, methods, parameters en constants.

Attributes worden toegevoegd vóór de declarations waarnaar ze verwijzen. Bekijk de volgende voorbeelden van de RFC:

<>
class Foo
{
	<>
	public const FOO = 'foo';

	<>
	public $x;

	<>
	public function foo(<> $bar) { }
}

$object = new <> class () { };

<>
function f1() { }

$f2 = <> function () { };

$f3 = <> fn () => 1;

Attributes kunnen voor of na een doc-block comment worden toegevoegd:

<>
/** docblock */
<>
function foo() {}

Elke declaration kan een of meerdere attributen hebben en elke attribute kan een of meer bijbehorende values hebben:

<>
<<SingleArgument(0)>>
<<FewArguments('Hello', 'World')>>
function foo() {}

Bekijk de RFC voor een meer gedetailleerd overzicht van PHP attributes, use cases en alternatieve syntax.

Nieuwe PHP functions

PHP 8 brengt verschillende nieuwe functions naar de taal:

str_contains

Voor PHP 8 waren strstr en strpos de typische opties voor developers om te zoeken naar een needle binnen een opgegeven string. Het probleem is dat beide functions niet erg intuïtief zijn en het gebruik ervan kan verwarrend zijn voor nieuwe PHP ontwikkelaars. Zie het volgende voorbeeld:

$mystring = 'Managed WordPress Hosting';
$findme = 'WordPress';
$pos = strpos($mystring, $findme);

if ($pos !== false) {
	echo "The string has been found";
} else {
	echo "String not found";
}

In het bovenstaande voorbeeld gebruikten we de comparison operator !== die ook controleert of twee values van hetzelfde type zijn. Dit voorkomt dat we een foutmelding krijgen als de positie van de needle 0 is:

“Deze function kan Boolean FALSE retourneren, maar het kan ook een non-Boolean value die evaluates naar FALSE. […] Gebruik de === operator om de teruggegeven value van deze function te testen.”

Bovendien bieden verschillende frameworks helper functions om te zoeken naar een value binnen een gegeven string (bekijk Laravel Helpers documentatie als voorbeeld).

Deze RFC stelt de introductie voor van een nieuwe function die het mogelijk maakt om binnen een string te zoeken: str_contains.

str_contains ( string $haystack , string $needle ) : bool

Het gebruik ervan is vrij eenvoudig. str_contains controleert of $needle wordt gevonden in $haystack en retourneert dienovereenkomstig true of false.

Dankzij str_contains kunnen we dus de volgende code schrijven:

$mystring = 'Managed WordPress Hosting';
$findme   = 'WordPress';

if (str_contains($mystring, $findme)) {
	echo "The string has been found";
} else {
	echo "String not found";
}

Dit is veel beter leesbaar en bovendien minder vatbaar voor fouten (zie hier de code in actie).

Op moment van schrijven is str_contains hoofdlettergevoelig, maar dit kan in de toekomst veranderen.

Het voorstel om str_contains toe te voegen werd aangenomen met 43 stemmen voor en 9 stemmen tegen.

str_starts_with() and str_ends_with()

Naast de function str_contains, zijn er nog twee andere functions toegevoegd die het mogelijk maken om binnen een bepaalde string te zoeken naar een needle: str_starts_with en str_ends_with.

Deze nieuwe functions controleren of een bepaalde string begint of eindigt met een andere string:

str_starts_with (string $haystack , string $needle) : bool
str_ends_with (string $haystack , string $needle) : bool

Beide functions retourneren false als $needle langer is dan $haystack.

Volgens Will Hudgins, de auteur van deze RFC,

“De functionaliteit str_starts_with en str_ends_with is zó nodig dat veel grote PHP frameworks het al ondersteunen, waaronder Symfony, Laravel, Yii, FuelPHP en Phalcon.”

Dankzij hen kunnen we nu suboptimale en minder intuïtieve functions vermijden als substr, strpos. Beide functions zijn hoofdlettergevoelig:

$str = "WordPress";
if (str_starts_with($str, "Word")) echo "Found!";

if (str_starts_with($str, "word")) echo "Not found!";

Je kan deze code hier in actie zien.

De RFC heeft deze goedgekeurd met 51 voor en 4 stemmen tegen.

get_debug_type

get_debug_type is een nieuwe PHP function die het type van een variabele retourneert. De nieuwe function werkt op een vergelijkbare manier als de gettype function, maar get_debug_type retourneert native names en zorgt bij class names voor een resolve.

Dit is een verbetering voor de taal, omdat gettype() niet erg nuttig is voor type checking.

De RFC geeft twee handige voorbeelden om het verschil tussen de nieuwe functions get_debug_type() en gettype() beter te begrijpen. Het eerste voorbeeld toont de werking van gettype:

$bar = [1,2,3];

if (!($bar instanceof Foo)) { 
	throw new TypeError('Expected ' . Foo::class . ', got ' . (is_object($bar) ? get_class($bar) : gettype($bar)));
}

Met PHP 8 kan je in plaats daarvan get_debug_type gebruiken:

if (!($bar instanceof Foo)) { 
	throw new TypeError('Expected ' . Foo::class . ' got ' . get_debug_type($bar));
}

De volgende tabel toont de returning values van get_debug_type en gettype:

Value gettype() get_debug_type()
1 integer int
0.1 double float
true boolean bool
false boolean bool
null NULL null
“WordPress” string string
[1,2,3] array array
A class with name “Foo\Bar” object Foo\Bar
An anonymous class object [email protected]

Overige RFC’s

Op moment van schrijven zijn er nog een aantal RFC’s voor PHP 8 die zich nog in de draft fase en/of pending implementation fase bevinden. We voegen deze toe zodra ze hun status hebben veranderd in “implemented”.

Hier is een korte lijst met overige goedgekeurde verbeteringen die deel zullen uitmaken van PHP 8:

  1. Stringable interface: deze RFC introduceert een Stringable interface die automatisch wordt toegevoegd aan classes die de __to String() method Het voornaamste doel is om hier de union type string|Stringable te gebruiken.
  2. Nieuwe DOM Living Standard API’s in ext/dom: deze RFC stelt voor om de huidige DOM Living Standard te implementeren in de PHP DOM extensie door nieuwe interfaces en public properties te introduceren.
  3. Static return type: PHP 8 introduceert het gebruik van static als return type, naast self en parent
  4. Variable syntax tweaks: deze RFC lost enkele resterende inconsistenties op in de variable syntax van PHP..
PHP 8 komt later dit jaar en zal veel veranderingen en verbeteringen met zich meebrengen. 🚀 Lees onze gedetailleerde beschrijving van alle nieuwe features!Click to Tweet

Samenvatting

Wat een rit! In dit artikel hebben we alle belangrijke veranderingen en verbeteringen besproken die worden verwacht met de release van PHP 8. Degene waar we het meest op wachten is toch wel de Just in Time Compiler, maar er komt nog veel meer aan met PHP 8.

Zorg dat je deze blogpost onder je favorieten opslaat, omdat we meer dingen aan deze lijst zullen toevoegen zodra ze zijn goedgekeurd. 🤓

Nu is het jouw beurt: ben je klaar om de aankomende PHP functies te testen? Op welke kan jij niet wachten? Je kan je antwoord in het reactiegedeelte hieronder kwijt.


Als je dit artikel leuk vond, dan ga je Kinsta’s WordPress hosting platform ook heel erg leuk vinden! Of het nu gaat om het versnellen van je website of de 24/7 support van ons ervaren WordPress-team. Onze door Google Cloud aangedreven infrastructuur is gericht op automatische schaalbaarheid, prestaties en beveiliging. Laat ons jou het Kinsta verschil tonen! Bekijk onze pakketten