PHP 8 er officielt frigivet til den generelle tilgængelighed den 26. november 2020!

Denne nye store opdatering bringer en hel række optimeringer og kraftfulde funktioner til sproget, og vi er glade for at køre dig gennem de mest interessante ændringer, der giver os mulighed for at skrive bedre kode og opbygge mere kraftfulde applikationer.

PHP 8 released
PHP 8.0 Announcement Addendum

Er du klar? Lad os dykke ned!

PHP JIT (Just in Time Compiler)

Den mest anerkendte funktion, der følger med PHP 8, er Just-in-time (JIT)  Compiler. Hvad handler JIT om?

RFC forslaget beskriver JIT som følgende:

”PHP JIT implementeres som en næsten uafhængig del af OPcache. Det kan være aktiveret / deaktiveret på PHP compile tid og ved kørselstidspunkt. Når det er aktiveret, gemmes oprindelig kode for PHP-filer i en yderligere region i den OPCache delte hukommelse og op_array → opcodes[]. Handler(e) holder pegepunkter til indgangspunkterne for JIT-ed-kode. ”

Så hvordan kom vi til JIT, og hvad er forskellen mellem JIT vs OPcache?

For bedre at forstå, hvad JIT er til PHP, så lad os se hurtigt på, hvordan PHP kører fra kildekoden til det endelige resultat.

PHP-udførelsen er en 4-trins proces:

Det følgende billede viser en visuel repræsentation af den grundlæggende PHP-eksekveringsproces.

Grundlæggende PHP-eksekveringsproces
Grundlæggende PHP-eksekveringsproces

Så hvordan gør OPcache PHP hurtigere? Og hvilke ændringer i udførelsesprocessen med JIT?

OPcache extension

PHP er et tolket sprog. Dette betyder, at når et PHP-script kører, tolker, kompilerer og udfører tolken koden igen og igen på hver anmodning. Dette kan resultere i spild af CPU-ressourcer og ekstra tid.

Det er her en OPcache extension kommer i spil:

“OPcache forbedrer PHP-ydeevne ved at gemme forudkompileret script-bytecode i delt hukommelse og dermed fjerne behovet for PHP at indlæse og analysere scripts på hver anmodning.”

Med OPcache aktiveret gennemgår PHP-fortolkeren kun 4-trinsprocessen nævnt ovenfor, når scriptet kører for første gang. Da PHP-bytekoder gemmes i delt hukommelse, er de straks tilgængelige som mellemliggende repræsentation på lavt niveau og kan udføres med det samme på Zend VM.

PHP eksekveringsproces med OPcache aktiveret
PHP eksekveringsproces med OPcache aktiveret

Fra PHP 5.5 er en Zend OPcache extension tilgængelig som standard, og du kan kontrollere, om du har den korrekt konfigureret ved blot at kalde phpinfo() fra et script på din server eller tjekke din php.ini-fil (se OPcache-konfigurationsindstillinger).

Foreslået læsning: How to Improve PHP Memory Limit in WordPress.

Zend OPcache-sektion på en phpinfo-side
Zend OPcache-sektion på en phpinfo-side

Preloading

OPcache er for nylig blevet forbedret med implementeringen af preloading, en ny OPcache-funktion tilføjet med PHP 7.4. Forudindlæsning giver en måde at gemme et specificeret sæt scripts i OPcache-hukommelse “før en applikationskode køres”, men det medfører ikke konkrete ydelse-forbedringer for typiske webbaserede applikationer.

Du kan læse mere om preloading i vores introduktion til PHP 7.4.

Med JIT bevæger PHP sig et skridt fremad.

JIT — The Just in Time Compiler

Selv hvis opcodes er i form af mellemliggende repræsentation på lavt niveau, skal de stadig samles til maskinkode. JIT “introducerer ikke nogen yderligere IR (Mellem-repræsentation) -formular”, men bruger DynASM (Dynamic Assembler til kodegenereringsmotorer) til at generere native code direkte fra PHP-byte-kode.

Kort sagt, JIT oversætter de varme dele af den mellemliggende kode til maskinkode. Ved at omgå kompilering kunne det medføre betydelige forbedringer i performance og hukommelsesforbrug.

Zeev Surasky, medforfatter til PHP JIT-forslaget, viser, hvor meget beregninger der ville være hurtigere med JIT:

Men ville JIT effektivt forbedre WordPress performance?

JIT for Live Web Apps

I henhold til JIT RFC, skal implementeringen af ​​just in time compiler forbedre PHP performance. Men ville vi virkelig opleve sådanne forbedringer i virkelige apps som WordPress?

De tidlige test viser, at JIT ville få CPU-intensive arbejdsbelastninger til at køre betydeligt hurtigere, men RFC advarer:

”… ligesom de foregående forsøg – det ser ud til, at det i øjeblikket ikke markant forbedrer apps i det virkelige liv som WordPress (med opcache.jit=1235 326 req/sek vs 315 req/sek).

Det er planlagt at give en ekstra indsats, forbedre JIT til apps i det virkelige liv, ved hjælp af profilering og spekulative optimeringer.”

Når JIT er aktiveret, køres koden ikke af Zend VM, men af ​​selve CPU’en, og dette ville forbedre hastigheden i beregningen. Webapps som WordPress er også afhængige af andre faktorer som TTFB, databaseoptimering, HTTP-anmodninger osv.ú

PHP 8 performance diagram
Relativt JIT-bidrag til PHP 8-ydeevne (Billedekilde: PHP 8.0 Announcement Addendum)

Så vi skal ikke forvente et markant løft i PHP-udførelseshastigheden, når det kommer til WordPress og lignende apps. Ikke desto mindre kunne JIT give flere fordele for udviklere.

Ifølge Nikita Popov:

”Fordelene ved JIT-kompilatoren er nogenlunde (og som allerede beskrevet i RFC):

  • Betydelig bedre ydelse for numerisk kode.
  • Lidt bedre ydelse til “typisk” PHP-webapplikationskode.
  • Potentialet for at flytte mere kode fra C til PHP, fordi PHP nu vil være tilstrækkeligt hurtigt. ”

Så selvom JIT næppe vil bringe enorme forbedringer af WordPress-ydeevne, vil den opgradere PHP til det næste niveau, hvilket gør det til et sprog, hvor mange funktioner nu kunne skrives direkte på.

Ulempen er dog den større kompleksitet, der kan føre til stigende omkostninger til vedligeholdelse, stabilitet og debugging. Ifølge Dmitry Stogov:

”JIT er ekstremt simpelt, men alligevel øger det niveauet for hele PHP-kompleksiteten, risikoen for ny slags bugs og omkostningerne til udvikling og vedligeholdelse.”

Forslaget om at medtage JIT i PHP 8 blev vedtaget med 50 til 2 stemmer.

PHP 8 forbedringer og nye features

Bortset fra JIT kan vi forvente mange funktioner og forbedringer med PHP 8. Den følgende liste er vores håndplukkede valg af de kommende tilføjelser og ændringer, der skal gøre PHP mere pålidelig og effektiv.

Constructor Property Promotion

Som et resultat af en løbende diskussion om, hvordan man forbedrer object ergonomics i PHP, foreslår Constructor Property Promotion RFC en ny og mere kortfattet syntaks, der vil forenkle ejendomserklæringen, hvilket gør den kortere og mindre overflødig.

Dette forslag vedrører kun promoverede parametre, dvs. de metode-parametre, der er præfixet med offentlige, beskyttede og private synlige keywords.

I øjeblikket skal alle egenskaber gentages flere gange (mindst fire gange), før vi kan bruge dem med objekter. Overvej følgende eksempel fra 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;
    }
}

Ifølge Nikita Popov, forfatteren af ​​RFC, er vi nødt til at skrive ejendomsnavnet mindst fire gange på tre forskellige steder: ejendomserklæringen, konstruktørparametrene og egenskabsopgaven. Denne syntaks er ikke særlig anvendelig, især i klasser med et godt antal egenskaber og mere beskrivende navne.

Denne RFC foreslår at flette konstruktøren og parameterdefinitionen. Så fra PHP 8 har vi en mere anvendelig måde at erklære parametre, og koden set ovenfor kan ændres som vist nedenfor:

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

Og det er det. Så vi har en ny måde at markedsføre egenskaber, der er kortere, mere læselige og mindre tilbøjelige til fejl. Ifølge Nikita:

Det er en simpel syntaktisk transformation, som vi laver. Men det reducerer mængden af kedelplade-kode, du er nødt til at skrive for værdiobjekter især …

Ejendomserklæringen transformeres, da vi eksplicit havde erklæret disse egenskaber, og vi kan bruge Reflection-API til at introspektere egenskabsdefinitioner før udførelsen (se Desugaring):

Reflektion (og andre introspektionsmekanismer) vil observere tilstanden efter desugaring. Dette betyder, at promoverede egenskaber vises på samme måde som eksplicit deklarerede egenskaber, og promoverede konstruktørargumenter vises som almindelige konstruktørargumenter.

// 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

Vi har ingen begrænsninger i brugen af ​​arv sammen med promoverede parametre. Under alle omstændigheder er der ikke et bestemt forhold mellem forældre og child class construction. Ifølge Nikita:

Normalt siger vi, at metoder altid skal være kompatible med den overordnede metode. […] men denne regel gælder ikke for konstruktøren. Så konstruktøren hører virkelig til en enkelt klasse, og konstruktører mellem forældre og børn klasse behøver ikke at være kompatible på nogen måde.

Her er et eksempe:

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);
    }
}

Hvad der ikke er tilladt med promoverede egenskaber

Fremme egenskaber er tilladt i ikke-abstrakte konstruktører og træk, men der er flere begrænsninger, der er værd at nævne her.

Abstract Constructors

Promoverede egenskaber er ikke tilladt i abstrakte klasser og grænseflader:

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

En af de mest bemærkelsesværdige begrænsninger er relateret til nullability. Tidligere, da vi brugte en type, der ikke var eksplicit nullable, men med en nul standardværdi, var typen implicit nullable. Men med egenskabstyper har vi ikke denne implicitte opførsel, fordi promoverede parametre kræver en ejendomserklæring, og den nullable type skal eksplicit erklæres. Se følgende eksempel fra 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

Da konverterbar ikke er en understøttet type for egenskaber, har vi ikke tilladelse til at bruge den konverterbare type i promoverede egenskaber :

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

Kun et synligt keyword kan bruges med promoverede parametre, så det er ikke tilladt at erklære konstruktøregenskaber med var keyword (se følgende eksempel fra RFC) :

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

Vi kan kombinere promoverede egenskaber og eksplicitte egenskaber i samme klasse, men egenskaber kan ikke erklæres to gange :

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

Årsagen her er, at den erklærede type adskiller sig fra den variadiske parameter, som faktisk er en matrix :

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

Yderligere læsninger

For at se nærmere på Costructor Property Promotion, lyt til dette interview med Nikita Popov. For et dybt overblik over object ergonomics i PHP, se dette indlæg og følgende interview med Larry Garfield.

Validering af abstrakte egenskabsmetoder

Traits er defineret som “en mekanisme til genanvendelse af kode på enkelt arvsprog som PHP”. Typisk bruges de til at erklære metoder, der kan bruges i flere klasser.

En egenskab kan også indeholde abstrakte metoder. Disse metoder erklærer simpelthen metodens signatur, men metodens implementering skal ske inden for klassen ved hjælp af egenskaben.

I henhold til PHP-manualen

“Traits understøtter brugen af ​​abstrakte metoder til at stille krav til exhibiting class.”

Dette betyder også, at signaturer til metoderne skal matche. Med andre ord skal typen og antallet af nødvendige argumenter være den samme.

I hvert fald håndhæves signatur-validering ifølge Nikita Popov, forfatter af RFC, i øjeblikket kun spottet:

Følgende eksempel fra Nikita vedrører den første sag (ikke håndhævet underskrift):

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) {}
}

Når det er sagt, foreslår denne RFC altid at kaste en dødelig fejl, hvis implementeringsmetoden ikke er kompatibel med den abstrakte egenskabsmetode, uanset dens oprindelse:

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

Denne RFC er enstemmig godkendt.

Inkompatible metodetegn

I PHP kaster arvefejl på grund af inkompatible metode-signaturer enten en dødelig fejl eller en advarsel afhængigt af, hvad der forårsager fejlen.

Hvis en klasse implementerer en grænseflade, kaster ukompatible metode-signaturer en dødelig fejl. I henhold til Object Interfaces documentation:

”Klassen, der implementerer grænsefladen, skal bruge en metode-signatur, der er kompatibel med LSP (Liskov Substitution Principle). Hvis du ikke gør det, vil det medføre en dødelig fejl. ”

Her er et eksempel på en arvefejl med en grænseflade:

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

I PHP 7.4 ville koden ovenfor kaste følgende fejl:

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

En funktion i en child class med en inkompatibel signatur ville kaste en advarsel. Se følgende kode fra RFC:

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

I PHP 7.4 ville koden ovenfor blot kaste en advarsel:

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

Nu foreslår denne RFC altid at kaste en dødelig fejl ved underskrifter med inkompatibel metode. Med PHP 8 ville den kode, vi så tidligere ovenfor, bede om følgende:

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 der starter med et negativt indeks

I PHP, hvis en matrix starter med et negativt indeks (start_index <0), starter de følgende indekser fra 0 (mere om dette i array_fill dokumentation). Se på følgende eksempel:

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

I PHP 7.4 ville resultatet være følgende:

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

Nu foreslår denne RFC at ændre ting, så det andet indeks ville være start_index + 1, uanset værdien af start_index.

I PHP 8 ville koden ovenfor resultere i følgende array:

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

Med PHP 8 ændrer arrays der begynder med et negativt indeks deres opførsel. Læs mere om bagudkompatibiliteter i RFC.

Union Types 2.0

Union types accepterer værdier, der kan være af forskellige typer. I øjeblikket yder PHP ikke support til fagtyper med undtagelse af syntaks ?Type og den specielle iterable type.

Før PHP 8 kunne union types kun specificeres i phpdoc-kommentarer, som vist i følgende eksempel fra 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;
	}
}

Nu foreslår the Union types 2.0 RFC at tilføje support til union types i funktionssignaturer, så vi ikke vil stole på inline-dokumentation mere, men vil definere union types med en T1 | T2 | ... syntaks i stedet:

class Number {
	private int|float $number;

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

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

Som forklaret af Nikita Popov i RFC,

”At støtte fagforeningstyper på sproget giver os mulighed for at flytte flere typeoplysninger fra phpdoc til funktionsunderskrifter med de sædvanlige fordele, dette medfører:

  • Types håndhæves faktisk, så fejl kan fanges tidligt.
  • Fordi de håndhæves, er type-oplysninger mindre tilbøjelige til at blive forældede eller gå glip af kanter.
  • Types kontrolleres under arv, hvilket håndhæver Liskov-substitutionsprincippet.
  • Types er tilgængelige via Reflektion.
  • Syntaxen er meget mindre kedelplade-y end phpdoc. ”

Union types understøtter alle tilgængelige typer med nogle begrænsninger:

  • void type understøttes kun i union types, men det er ikke tilladt at bruge den som en selvstændig type.
  • null type af ​​den nullable type (?T) er også tilladt, hvilket betyder T|null, men vi har ikke tilladelse til at medtage?T-notationen i union types (?T1|T2 er ikke tilladt, og vi bør i stedet bruge T1|T2|null) .
  • Da mange funktioner (dvs. strpos(), strstr(), substr() osv.) Inkluderer falsk blandt de mulige returtyper, understøttes den false pseudo type også.

Du kan læse mere om union types V2 i RFC.

Konsistente typefejl til interne funktioner

Når du sender en parameter af ulovlig type, opfører de interne og brugerdefinerede funktioner sig forskelligt.

Brugerdefinerede funktioner kaster en TypeError, men interne funktioner opfører sig på forskellige måder, afhængigt af flere forhold. Alligevel er den typiske opførsel at smide en advarsel og returnere null. Se følgende eksempel i PHP 7.4:

var_dump(strlen(new stdClass));

Dette ville resultere i følgende advarsel:

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

Hvis strict_types er aktiveret, eller hvis argument oplysninger specificerer typer, vil adfærden være anderledes. I sådanne scenarier registreres typefejlen og resulterer i en TypeError.

Denne situation ville føre til en række problemer, der er godt forklaret i RFC’s problemafdeling.

For at fjerne disse uoverensstemmelser foreslår denne RFC at oprette de interne parameter-parsing-API’er til altid at generere en ThrowError i tilfælde af en parametertilpasning.

I PHP 8 kaster koden ovenfor følgende fejl:

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

I PHP er throw en statement, så det er ikke muligt at bruge det på steder, hvor kun en expression er tilladt.

Denne RFC foreslår at konvertere throw statement  til et udtryk, så det kan bruges i enhver sammenhæng, hvor udtryk er tilladt. For eksempel arrow functions, null coalesce operator, ternary og elvis operators osv.

Se følgende eksempler fra 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

Et weak map er en samling af data (objekter), hvor nøgler refereres svagt, hvilket betyder, at de ikke forhindres i at blive opsamlet skrald.

PHP 7.4 tilføjede støtte til weak references som en måde at bevare en henvisning til et objekt, der ikke forhindrer selve objektet i at blive ødelagt. Som påpeget af Nikita Popov,

”Rå svage referencer er kun af begrænset brugbarhed i sig selv, og weak maps er meget mere almindeligt anvendt i praksis. Det er ikke muligt at implementere et effektivt weak map oven på PHP-svage referencer, fordi der ikke er mulighed for at registrere et destruction callback. ”

Derfor introducerer denne RFC en WeakMap-klasse for at oprette objekter, der kan bruges som svage weak map keys, der kan ødelægges og fjernes fra weak map, hvis der ikke er yderligere henvisninger til nøgleobjektet.

I langvarige processer ville dette forhindre hukommelse lækager og forbedre ydelsen. Se følgende eksempel fra RFC:

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

Med PHP 8 ville koden ovenfor give følgende resultat (se koden i action her):

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

Hvis du fjerner objektet, fjernes nøglen automatisk fra weak map:

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

Nu ville resultatet være følgende:

object(WeakMap)#1 (0) {
}

Se RFC for et nærmere kig på weak mapst. Forslaget blev enstemmigt godkendt.

Trailing commas i parameterliste

Trailing commas er kommaer knyttet til lister over elementer i forskellige sammenhænge. PHP 7.2 introducerede trailing commas i listesyntaks, PHP 7.3 introducerede trailing commas i function calls.

PHP 8 introducerer nu trailing commas i parameter lists med funktioner, metoder og lukninger, som vist i følgende eksempel:

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

Dette forslag blev vedtaget med 58 til 1 stemmer.

Allow ::class syntax på objekter

For at hente navnet på en klasse kan vi bruge Foo\Bar::class syntax. Denne RFC foreslår at udvide den samme syntaks til objekter, så det nu er muligt at hente navnet på klassen på et givet objekt som vist i eksemplet herunder:

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

Med PHP 8 giver $object:: class det samme resultat som get_class ($object). Hvis $object ikke er et objekt, kaster det en TypeError-undtagelse.

Dette forslag blev enstemmigt godkendt.

Attributes v2

Attributes, også kendt som annotationer, er en form for strukturerede metadata, der kan bruges til at specificere egenskaber for objekter, elementer eller filer.

Indtil PHP 7.4 var doc-kommentarer den eneste måde at tilføje metadata til erklæringer om klasser, funktioner osv. Nu introducerer Attributes v2 RFC attributes til PHP, der definerer dem som en form for strukturerede, syntaktiske metadata, der kan føjes til erklæringerne om klasser, egenskaber, funktioner, metoder, parametre og konstanter.

Attributes tilføjes før de erklæringer, de henviser til. Se følgende eksempler fra RFC:

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

	<>
	public $x;

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

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

<>
function f1() { }

$f2 = <> function () { };

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

Attributes kan tilføjes før eller efter en doc-block kommentar:

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

Hver erklæring kan have en eller flere attributter, og hver attribut kan have en eller flere tilknyttede værdier:

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

Se RFC for en dybere oversigt over PHP-attributter, brugssager og alternativ syntaks.

Named Arguments

Named arguments giver en ny måde at overføre argumenter til en funktion i PHP:

Named arguments tillader overførsel af argumenter til en funktion baseret på parameternavnet snarere end parameterpositionen.

Vi kan sende Named Arguments til en funktion ved blot at tilføje parameternavnet før dens værdi:

callFunction(name: $value);

Vi har også tilladelse til at bruge reserverede nøgleord som vist i eksemplet nedenfor:

callFunction(array: $value);

Men vi har ikke lov til at videregive et parameternavn dynamisk. Parameteren skal være en identifikator, og følgende syntaks er ikke tilladt:

callFunction($name: $value);

Ifølge Nikita Popov, forfatteren af ​​denne RFC, har named arguments flere fordele.

For det første vil named arguments hjælpe os med at skrive mere forståelig kode, fordi deres betydning er selvdokumenterende. Eksemplet nedenfor fra RFC forklarer sig selv:

array_fill(start_index: 0, num: 100, value: 50);

Named arguments er ordens-uafhængige. Dette betyder, at vi ikke er tvunget til at videregive arguments til en funktion i samme rækkefølge som funktionssignaturen:

array_fill(value: 50, num: 100, start_index: 0);

Det er også muligt at kombinere navngivne argumenter med positionelle arguments:

htmlspecialchars($string, double_encode: false);

En anden stor fordel ved named arguments er, at de kun tillader at specificere de arguments, vi rent faktisk vil ændre, og at vi ikke behøver at specificere standardargumenter, hvis vi ikke vil overskrive standardværdier. Følgende eksempel fra RFC gør det klart:

htmlspecialchars($string, default, default, false);
// vs
htmlspecialchars($string, double_encode: false);

Named arguments kan bruges med PHP-attributter, som vist i følgende eksempel fra RFC:

<<MyAttribute('A', b: 'B')>>
class Test {}

Men t sende positional arguments efter named arguments er imidlertid ikke tilladt og vil resultere i en kompilering tidsfejl. Det samme sker, når du sender det samme parameternavn to gange.

Named arguments er især nyttige med class deklarationer, fordi konstruktører normalt har et stort antal parametre, og navngivne argumenter giver en mere “ergonomisk” måde at erklære en class på.

For en nærmere oversigt over named arguments med begrænsninger, bagudkompatibiliteter og flere eksempler, se Named arguments RFC.

Nullsafe Operator

Denne RFC introducerer nullsafe operator $-> med short-circuit evaluation.

Ved short-circuit evaluation evalueres den anden operatør kun, hvis den første operatør ikke evaluerer til null. Hvis en operatør i en kæde evaluerer til null, stopper udførelsen af ​​hele kæden og evalueres til null.

Overvej følgende eksempler fra RFC:

$foo = $a?->b();

Hvis $a er null, kaldes metode b() ikke, og $foo er indstillet til null.

Se rfc:nullsafe_operator for yderligere eksempler, undtagelser og fremtidig rækkevidde.

Saner String to Number Comparisons

I tidligere PHP-versioner, når der foretages en ikke-streng sammenligning mellem strings og tal, kaster PHP først string til et tal og udfører derefter sammenligningen mellem heltal eller floats. Selvom denne adfærd er ret nyttig i flere scenarier, kan den give forkerte resultater, der også kan føre til fejl og/eller sikkerhedsproblemer.

Overvej følgende eksempel fra RFC:

$validValues = ["foo", "bar", "baz"];
$value = 0;
var_dump(in_array($value, $validValues));
// bool(true)

PHP 8 introducerer Saner string to number comparisons, der sigter mod at gøre string til antal sammenligninger mere rimelige. Med ordene fra Nikita Popov,

Denne RFC har til hensigt at give streng til antal sammenligninger en mere rimelig opførsel: Når du sammenligner med en numerisk streng, skal du bruge en tallesammenligning (samme som nu). Ellers konverterer du nummeret til streng og bruger en strengesammenligning.

Den følgende tabel sammenligner strengens opførsel med tidligere sammenligning af numre til PHP og i PHP 8:

Comparison    | Before | After
------------------------------
 0 == "0"     | true   | true
 0 == "0.0"   | true   | true
 0 == "foo"   | true   | false
 0 == ""      | true   | false
42 == "   42" | true   | true
42 == "42foo" | true   | false

Læs mere om de mange implikationer af denne ændring, og hvordan streng til tal-sammenligning ændres i PHP 8 i den officielle RFC fra Nikita Popov.

Saner Numeric Strings

I PHP falder strenge, der indeholder tal, ind i tre kategorier:

  • Numeric strings: strings, der indeholder et tal, der eventuelt indledes med mellemrum.
  • Leading-numeric string: strings, hvis indledende tegn er numeric strings, og efterfølgende tegn er ikke-numeriske.
  • Non-numeric string: strings falder ikke i nogen af ​​de foregående kategorier.

Numeric strings og ledende-numeriske strenge behandles forskelligt afhængigt af den udførte operation. For eksempel:

  • Explicit string to number conversions (i.e. (int) og (float) type casts) konverterer numeriske og ledende-numeriske strings numre. Eksplicit at konvertere en ikke-numerisk string til et tal producerer 0.
  • Explicit string to number conversions (dvs. ingen string_type-declaration) fører til forskellige resultater for numeriske og ikke-numeriske strenge. Ikke-numerisk string til antal konverteringer kaster en TypeError.
  • is_numeric() returnerer kun true for numeriske strenge.

Strengforskydninger, aritmetiske operationer, inkrement- og dekrementeringsoperationer, streng-til-streng-sammenligning og bitvise operationer fører også til forskellige resultater.

Denne RFC foreslår at:

Forene de forskellige numeric string modes i et enkelt koncept: Numeriske tegn kun med både ledende og efterfølgende hvidt mellemrum tilladt. Enhver anden type streíng er non-numeric og kaster TypeErrors, når den bruges i en numerisk sammenhæng.

Dette betyder, at alle strenge, der i øjeblikket udsender E_NOTICE “En ikke-velformet numerisk værdi, der er stødt på”, vil blive klassificeret igen i E_WARNING “En ikke-numerisk værdi, der er stødt på”, undtagen hvis den ledende-numeriske streng kun indeholdt efterfølgende hvidt mellemrum. Og de forskellige sager, der i øjeblikket udsender en E_WARNING, promoveres til TypeErrors.

For en dybere oversigt over numeriske strenge i PHP 8 med kodeeksempler, undtagelser og backward compatibility issues, se RFC.

Match Expression v2

Det nye match udtryk ligner stort set switch, men med sikrere semantik og giver mulighed for at returnere values.

For at forstå forskellen mellem de to kontrolstrukturer skal du overveje følgende switcheksempel fra RFC:

switch (1) {
	case 0:
		$result = 'Foo';
		break;
	case 1:
		$result = 'Bar';
		break;
	case 2:
		$result = 'Baz';
		break;
}
 
echo $result;
//> Bar

Vi kan nu få det samme resultat som koden ovenfor med følgende match udtryk:

echo match (1) {
	0 => 'Foo',
	1 => 'Bar',
	2 => 'Baz',
};
//> Bar

En stor fordel ved at bruge det nye match udtryk er, at mens switch sammenligner værdier løst (==), der potentielt fører til uventede resultater, med sammenligning er sammenligningen en identitetskontrol (===).

match udtrykket kan også indeholde flere kommaseparerede udtryk, der giver mulighed for mere kortfattet syntaks (kilde):

$result = match ($x) {
	// This match arm:
	$a, $b, $c => 5,
	// Is equivalent to these three match arms:
	$a => 5,
	$b => 5,
	$c => 5,
};

For yderligere eksempler og tilfælde af brug, se Match expression v2 RFC og PHP documentation.

Strengere kontrol af typen for Arithmetic/Bitwise Operators

I tidligere versioner af PHP var det tilladt at anvende arithmetic og bitwise operators på et array, ressource eller ikke-overbelastet objekt. Under alle omstændigheder var adfærden undertiden inkonsekvent.

I denne RFC viser Nikita Popov, hvor urimelig den adfærd kunne være med et simpelt eksempel:

var_dump([] % [42]);
// int(0)

Nikita forklarer, hvordan anvendelse af en aritmetisk eller bitvis operator på arrays, ressourcer eller ikke-overbelastede objekter førte til forskellige resultater:

Operators +, -, *, /, **:

  • Throw Error exception på array operand. (Ekskluderer+ hvis begge operander er array.)
  • Konverter en resource operand stille til ressource id’et som et heltal.
  • Konverter en objektoperand til heltal, mens du kaster en meddelelse.

Operators %, <<, >>, &, |, ^:

  • Konverter en matrixoperand stille til heltal nul, hvis det er tomt eller heltal, hvis det ikke er tomt.
  • Konverter en resource operand stille til resource id som et heltal.
  • Konverter en object operand til heltal, mens du kaster en meddelelse.

Operator ~:

  • Throw en TypeError exception for array, resource og object operands.

Operators ++ and –:

  • Gør intet, hvis operanden er en matrix, ressource eller et objekt.

Med PHP 8 ændres ting, og adfærden er den samme for alle aritmetiske og bitvise operatører:

Throw en TypeError exception for array, resource og object operands.

Nye PHP-funktioner

PHP 8 bringer flere nye funktioner til sproget:

str_contains

Før PHP 8 var strstr og strpos de typiske muligheder for udviklere at søge efter en nål inde i en given streng. Problemet er, begge funktioner betragtes ikke som meget intuitive, og deres brug kan være forvirrende for nye PHP-udviklere. Se følgende eksempel:

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

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

I eksemplet ovenfor brugte vi! == sammenligning operatøren, som også kontrollerer, om to værdier er af samme type. Dette forhindrer os i at få en fejl, hvis nålens placering er 0:

”Denne funktion returnerer muligvis Boolean FALSE, men kan også returnere en ikke-boolean værdi, der evalueres til FALSE. […] Brug === operatoren til at teste returnerings-værdien for denne funktion”

Derudover giver flere rammer hjælperfunktioner til at søge efter en værdi inde i en given streng (se Laravel Helpers dokumentation som et eksempel).

Nu foreslår denne RFC introduktion af en ny funktion, der gør det muligt at søge i en streng: str_concepts.

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

Dens brug er temmelig ligetil. str_concepts kontrollerer om $needle findes i $haystack og returnerer true eller false i overensstemmelse hermed.

Så takket være str_contains kan vi skrive følgende kode:

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

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

Hvilket er mere læseligt og mindre tilbøjeligt til fejl (se denne kode i action her).
På dette tidspunkt er str_containes store og små bogstaver, men dette kan ændre sig i fremtiden.

str_concepts-forslaget vedtaget med 43 til 9 stemmer.

str_starts_with() og str_ends_with()

Foruden str_concepts-funktionen tillader to nye funktioner at søge efter en needle inden i en given streng: str_starts_with og str_ends_with.

Disse nye funktioner kontrollerer, om en given streng starter eller slutter med en anden streng:

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

Begge funktioner returnerer false, hvis $needle er længere end $haystack.

Ifølge Will Hudgins, forfatteren af denne RFC,

str_starts_with– og str_ends_with-funktionaliteten er så almindeligt nødvendigt, at mange store PHP-rammer understøtter det, herunder Symfony, Laravel, Yii, FuelPHP og Phalcon.”

Takket være dem kunne vi nu undgå at bruge suboptimale og mindre intuitive funktioner som substr, strpos. Begge funktioner er store og små bogstaver:

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

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

Du kan se denne kode i handling her.

Denne RFC er godkendt med 51 til 4 stemmer.

get_debug_type

get_debug_type er en ny PHP-funktion, der returnerer typen af en variabel. Den nye funktion fungerer på en ganske lignende måde som gettype funktion, men get_debug_type returnerer oprindelige type navne og løser klassens navn.

Det er en god forbedring for sproget, da gettype() ikke er nyttigt til typekontrol.

RFC giver to nyttige eksempler for bedre at forstå forskellen mellem den nye get_debug_type() -function og gettype(). Det første eksempel viser gettype på arbejdet:

$bar = [1,2,3];

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

Med PHP 8 kunne vi i stedet bruge get_debug_type:

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

Med PHP 8 kunne vi bruge get_de Følgende tabel viser returnerende værdier af get_debug_type og 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 class@anonymous

Yderligere RFC’er

På dette tidspunkt er flere RFC’er, der er målrettet mod PHP 8, stadig i udkast og/eller afventer implementering. Vi tilføjer dem, så snart deres status ændres til “Implementeret”.

Her er en hurtig liste over yderligere godkendte forbedringer, der vil være en del af PHP 8:

  1. Stringable interface: denne RFC¨ introducerer en stringable grænseflade, der automatisk føjes til klasser, der implementerer __to String() -metoden. Det vigtigste mål her er at bruge string|Stringable union type.
  2. Nye DOM Living Standard API’er i ext/dom: denne RFC foreslår at implementere den nuværende DOM Living Standard til PHP DOM extension ved at introducere nye grænseflader og offentlige egenskaber.
  3. Static return type: PHP 8 introducerer brugen af ​​static som returtype ud for self– og parent typer.
  4. Variable Syntax Tweaks: denne RFC løser nogle resterende uoverensstemmelser i PHPs variable syntax

PHP 8 Ydelse Benchmarks

Hvis du undrer dig over, hvor hurtigt PHP 8 er, har vi svaret. Vi benchmarkede 20 PHP-platforme/-konfigurationer på 7 forskellige PHP-versioner (5.6, 7.0, 7.1, 7.2, 7.3 og 8.0).

PHP 8.0 viste sig som vinderen på de fleste platforme, der understøtter det, inklusive WordPress og Laravel.

Kompileret PHP benchmarks for de bedste platforme
Kompileret PHP benchmarks for de bedste platforme

For eksempel kan WordPress på PHP 8.0 håndtere 18,4% flere anmodninger i sekundet end PHP 7.4. Ligeledes kan Laravel på PHP 8.0 køre 8,5% flere anmodninger i sekundet end PHP 7.3.

Hvis dit websted eller din app er fuldt ud kompatibel med PHP 8.0, bør du planlægge at opdatere din servers miljø til PHP 8.0 så hurtigt som muligt. Du (og dine brugere) vil helt sikkert sætte pris på dens ydeevnefordele. Test dog venligst dit websted grundigt, før du opdaterer.

Du kan læse vores PHP-benchmark-artikel for mere information, såsom detaljerede ydeevnedata, indsigt og smukke grafer!

Resumé

Hvilken tur! I dette indlæg dækkede vi de mest interessante optimeringer og funktioner, der kommer med PHP 8. Den mest ventede er helt sikkert the Just in Time compiler, men der er så meget mere med PHP 8.

Sørg for at bogmærke dette blogindlæg til din fremtidige reference. 🤓

Nu er det din tur: er du klar til at teste de nye PHP-funktioner? Hvilken er din favorit? Slip en linje i kommentarfeltet nedenfor.

Carlo Daniele Kinsta

Carlo er en passioneret elsker af webdesign og frontend udvikling. Han har arbejdet med WordPress i over 10 år, også i samarbejde med italienske og europæiske universiteter og uddannelsesinstitutioner. Han har skrevet snesevis af artikler og guides om WordPress, udgivet både på italienske og internationale hjemmesider samt på trykte magasiner. Du kan finde Carlo på X og LinkedIn.