[vc_row row_height_percent=“0″ overlay_alpha=“50″ gutter_size=“3″ column_width_use_pixel=“yes“ shift_y=“0″ z_index=“0″ uncode_shortcode_id=“125606″ column_width_pixel=“1000″][vc_column][vc_custom_heading heading_semantic=“h1″ text_size=“h1″ uncode_shortcode_id=“137298″]
PHP 8.1 – Enums, Fibers, Performance
[/vc_custom_heading][vc_single_image media=“73827″ media_width_percent=“85″ uncode_shortcode_id=“172360″][uncode_info_box items=“Author|Large_avatar_size|inline_avatar|display_prefix,Date“ separator=“pipe“][vc_empty_space empty_h=“2″][vc_custom_heading uncode_shortcode_id=“126385″]
PHP 8.1 – Release im Überblick
[/vc_custom_heading][/vc_column][/vc_row][vc_row row_height_percent=“0″ overlay_alpha=“50″ gutter_size=“3″ column_width_use_pixel=“yes“ shift_y=“0″ z_index=“0″ uncode_shortcode_id=“356064″ column_width_pixel=“1000″ css=“.vc_custom_1645447481114{margin-top: -54px !important;}“][vc_column][vc_column_text uncode_shortcode_id=“665962″]Die neuste Version von PHP 8.1 ist am 25.11.2021 erschienen. Auch wenn es nur ein kleinerer Punkt-Release ist, enthält die Version einige sehr interessante neue Features. Darunter gibt es ein paar einfache Funktionserweiterungen, zum Beispiel das neue Argument $options
rund um die hash-Funktionen, als auch ganz neue Syntax-Varianten. Dieser Beitrag beleuchtet die wichtigsten Neuerungen.
Was uns und PHP-Fans natürlich erfreut, ist, dass auch Version 8.1 wieder ein wenig schneller geworden ist. So gemessen von stitcher.io:
Falls du wissen willst, wofür PHP eigentlich verwendet wird und wie es funktioniert, schau einfach mal hier in unseren erklärenden Beitrag Was ist PHP?
[/vc_column_text][vc_single_image media=“73849″ caption=“yes“ media_width_percent=“80″ alignment=“center“ uncode_shortcode_id=“201999″][vc_column_text uncode_shortcode_id=“655208″]Auch synthetische Benchmarks bescheinigen PHP 8.1 eine mindestens 3 % bessere Performance zum Vorgänger und noch viel mehr zur weit verbreiteten Version 7.1.[/vc_column_text][vc_single_image media=“73848″ caption=“yes“ media_width_percent=“80″ alignment=“center“ uncode_shortcode_id=“142807″][vc_column_text uncode_shortcode_id=“466777″]Jetzt zu den neuen Features.[/vc_column_text][vc_empty_space empty_h=“3″][vc_column_text uncode_shortcode_id=“124202″]
Inhaltsverzeichnis
- Enums – Aufzählungen für saubere Konstanten
- Fibers – PHP asynchron ausführen durch Koroutinen
- Readonly -Eigenschaften für Klassen
- Intersection -Typen
- Der never -Rückgabewert
- Das final -Keyword für Konstanten
- Die array_is_list -Funktion
- fsync und fdatasync verhindern Datenverlust
- Array unpacking für Arrays mit String-Keys
- Neue Syntax für Closures
- Fazit: Jetzt schon Upgraden?
- Quellen
[/vc_column_text][vc_empty_space empty_h=“2″][vc_column_text uncode_shortcode_id=“865243″]
1. Enums
Enums sind Aufzählungen mit einer begrenzten Anzahl von möglichen Eigenschaften. Sie fungieren im Prinzip als eine Option zwischen Konstanten und Klassen. Ein einfaches Beispiel:
enum Status
{
case Entwurf; case Publiziert; case Archiviert; }
Diese Syntax ersetzt die etwas schwerfälligere Methode der Klassenkonstanten:
class Status {
public const Entwurf = 'Entwurf';
public const Publiziert = 'Publiziert';
public const Archiviert = 'Archiviert';
}
Ein enum
lässt sich als Typ weiterverwenden.
function setze_status(Status $status): void
{
}
So lässt sich bei Aufruf der Funktion sicherstellen, dass der richtig Typ übergeben wurde.
setze_status(Status::Entwurf);
Dabei kann ein case
auch einen Wert haben. Der muss entweder vom Typ string
oder int
sein. In diesem Fall handelt es sich um eine backed enumeration.
enum Farben: string
{
case ROT = '#ff0000';
case BLAU = '#0000ff';
case GELB = '#ffff00';
}
enum Fehler: int
{
case NICHTS = 0;
case ZUWENIG = -1;
case ZUVIEL = 1;
}
Um auf Namen und Wert zuzugreifen, gibt es Eigenschaften:
echo Farben::ROT->value; #=> #ff0000
echo Farben::ROT->name; #=> ROT
Enums sind strukturierte Konstanten. Sie können aber auch eigene Methoden haben.
enum Rolle: string
{
case ADMIN = 'admin';
case USER = 'user';
case SUPPORT = 'support';
public function icon(): string
{
return match($this)
{
Rolle::ADMIN => 'admin-icon.png',
Rolle::USER => 'user-icon.png',
Rolle::SUPPORT => 'support-icon.png'
}
}
}
match($this)
fungiert in diesem Zusammenhang wie ein switch
-Statement.
Enums selbst haben keinen state. Demnach gibt es keine Eigenschaften und ein Enum lässt sich auch nicht instanziieren. Es lassen sich jedoch ein oder mehrere Interfaces implementieren.
interface Farbenfroh
{
public function farbe(): string;
}
enum Karten implements Farbenfroh
{
case Herzen;
case Karos;
case Piks;
case Kreuze;
# Erfüllt den Interface-Vertrag
public function farbe(): string
{
return match($this) {
Karten::Herzen, Karten::Karos => 'Rot',
Karten::Piks, Karten::Kreuze => 'Schwarz'
};
}
# Ohne Interface geht auch
public function form(): string
{
return "Rechteck";
}
}
Mit einem trait
lässt sich Verhalten in Form von Methoden in Enums einmischen, ähnlich wie das auch schon bei Klassen möglich ist.
interface Farbenfroh
{
public function farbe(): string;
}
trait Rechteck
{
public function form(): string {
return 'Rechteck';
}
}
enum Karten implements Farbenfroh
{
use Rechteck;
case Herzen;
case Karos;
case Piks;
case Kreuze;
public function farbe(): string
{
return match($this) {
Karten::Herzen, Karten::Karos => 'Rot',
Karten::Piks, Karten::Kreuze => 'Schwarz'
};
}
}
echo Karten::Herzen->form(); #=> Rechteck
2. Fibers – PHP asynchron ausführen durch Koroutinen
Mit Fibers gibt es das erste echte Feature für die asynchrone Ausführung in PHP. PHP verlässt sich seit seinen Anfängen darauf, dass parallele Exekution (Mulithreading) durch den Webserver (Apache etc.) gehandelt wird. Alles in allem ein sehr gute Strategie, weil es viel Komplexität vor den Entwicklern versteckt und schließlich hat der Erfolg von PHP auch gezeigt, dass dies bisher eine exzellente strategische Entscheidung war. Die Popularität von JavaScript und Go zeigen aber auch, dass PHP hier eine konkrete Lücke hat, die das Core-Team in Zukunft vermutlich, wenigstens teilweise schließen möchte.
Hier ein Beispiel zur Verwendung des Fibers-Features:
$request1 = new Http("get", "http://example.com");
$request2 = new Http("get", "http://example.com");
foreach ([$request1, $request2] as $request){
$child = new Fiber(function() use ($request){
// ::await blockiert lediglich den aktuellen Thread. Alle anderen Fibers können weiterlaufen
Async::await($request->connect());
Async::await($request->fetch());
// Code hier läuft sobald die URL gelesen wurde/
// Sie wartet also nicht auf die anderen Fetch-Prozesse
});
$child->start();
}
# Aktuell blokiert ::run() das Program und nichts kann weiterlaufen
# bis alle Fibers fertig sind.
# In der Zukunft soll es Top Level-Fiber geben, die die gesamte App
# asynchron machen.
Async::run();
Quelle: https://github.com/nox7/async-php-8-io-http
Sehr ausführliche Informationen zur Verwendung von Fibers finden sich bei PHP.Watch.
Es ist davon auszugehen, dass hauptsächlich die Framework-Entwickler von diesem Feature Gebrauch machen, da parallele Programmierung sehr herausfordernd sein kann.[/vc_column_text][vc_empty_space empty_h=“2″][vc_empty_space empty_h=“2″][vc_column_text uncode_shortcode_id=“712317″]
3. Readonly-Eigenschaften für Klassen
Neben den Keywords final
und abstract
kennt PHP 8.1 jetzt das Keyword readonly
. Es kann nur im Zusammenhang mit Eigenschaften für Klassen verwendet werden. Ein Beispiel:
class Ergebnis
{
public readonly string $wert;
public function __construct(string $wert)
{
$this->wert = $wert;
}
}
Die Variable $wert
kann nur bei Instanziierung gesetzt werden und dann nicht mehr.
$ergebnis = new Ergebnis('123');
$ergebnis->key = '456'; # eine Exception wird ausgelöst
Wofür könnte das gut sein? Selbstverständlich lässt sich auch einfach mit isset
überprüfen, ob eine Variable schon erstellt wurde. Es ist aber denkbar, dass im Zusammenhang zum Beispiel mit der Fibers-Funktionalität solche syntaktischen Lösungen sauberer aussehen. Denkbar wäre eine Klasse, die versucht, einen Wert von mehreren URLs abzurufen. Sobald die erste Response reinkommt, wird der readonly
-Wert erstellt. Alle nachfolgenden Versuche erzeugen eine Exception, die dann programmtechnisch wieder verarbeitet werden kann.
4. Intersection-Typen
PHP bietet seit Version 8.0 die Möglichkeit, Typen zu kombinieren, auch union types genannt. Mit |
getrennte Typen erlauben den einen oder anderen Typen, wie im folgenden Beispiel.
class Student
{
private int|float $roomNo;
public function setRoomNo(int|float $roomNo): void {
$this->roomNo;
}
public function getRoomNo(): int|float {
return $this->roomNo;
}
}
$newStudent1 = new Student;
$newStudent1->setRoomNo(25.0);
$newStudent2 = new Student;
$newStudent2->setRoomNo(4);
echo "Student 1 number is " .$newStudent1->getRoomNo(). "<br>";
echo "Student 2 number is " .$newStudent2->getRoomNo();
(Quelle: educative).
$roomNo
darf also int
ODER float
sein. Mittels & lässt sich jetzt eine UND-Voraussetzung bestimmen.
public function paginate(
Countable&Iterator $collection,
int $offset,
int $slice,
): array {
}
Dieses Beispiel definiert den Funktions-Parameter $collection, der sowohl das Interface Countable als auch das Interface Iterator implementiert haben muss. Dies verhindert, dass der Programmierer dieses interface
erst selbst definieren muss, zum Beispiel so: interface CountableIterator extends Countable, Iterator
.
5. Der never
-Rückgabewert
Klingt erstmal ungewöhnlich, aber es gibt Funktionen, die sollen überhaupt nie etwas zurückgeben. Beispielsweise wenn sie nur eine Ausnahme auslösen, eine Weiterleitung auslösen oder das Skript mit exit
beenden.
function visit($url): never
{
if (true)
{
return 'Ergebnis'; # Gibt Fehler aus.
}
header('Location: /');
}
Das never
-Keyword verhindert, dass die visit
-Funktion return
verwenden darf. Dies dient dazu, Fehler in der Zukunft zu vermeiden.
6. Das final
-Keyword für Konstanten
Man soll es kaum glauben, aber es ist tatsächlich möglich Konstanten in Klassen zu überschreiben, wenn ein Interface oder eine Vererbung das wünscht. Das final
-Keyword verhindert dies jetzt. Allerdings nur für public
und protected
Konstanten.
class Bla
{
final public const A = "Bla";
}
class Blubb extends Bla
{
public const = "Blubb"; # Ein fatal error verhindert dies
}
7. Die array_is_list
-Funktion
Diese Funktion gibt true
zurück, falls das array
eine echte Liste mit sequentiellen Integer-Werten ist, die lückenlos sind und mit 0
beginnen.
array_is_list([]); # true
array_is_list([1, 2, 3]); # true
array_is_list(['hostpress', 2, 3]); # true
array_is_list(['hostpress', 'wordpress']); # true
array_is_list([0 => 'hostpress', 'wordpress']); # true
array_is_list([0 => 'hostpress', 1 => 'wordpress']); # true
# Key startet nicht bei 0
array_is_list([1 => 'apple', 'orange']); # false
# Keys in der falschen Reihenfolge
array_is_list([1 => 'apple', 0 => 'orange']); # false
# Keys sind nicht vom Typ Integer
array_is_list([0 => 'apple', 'foo' => 'bar']); # false
# Keys nicht lückenlos
array_is_list([0 => 'apple', 2 => 'bar']); # false
8. fsync
undfdatasync
verhindern Datenverlust
Erfreulich sind diese beiden neuen Funktionen, weil sie ein potenziell schwerwiegendes Problem lösen. Besucher füllt Formular aus, sendet ab, erhält E-Mail, aber die Daten sind nicht auf Platte geschrieben, der Bestätigungslink funktioniert nicht. Wer schon länger mit PHP arbeitet, dem ist das vielleicht schonmal passiert. Schreiboperationen können manchmal missglücken, obwohl PHP zurückgibt, dass alles gut gegangen ist. Manchmal speichert das Betriebssystem die Daten nur im Zwischenspeicher, ohne sie final auf den Festspeicher zu schreiben. fsync
undfdatasync
versprechen Abhilfe. So sieht die Verwendung aus:
$file = 'test.txt';
$fh = fopen($file, 'w');
fwrite($fh, 'hostpress');
fwrite($fh, "\r\n");
fwrite($fh, 'is super fast');
fsync($fh);
fclose($fh);
9. Array unpacking für Arrays mit String-Keys
Arrays ineinander kopieren geht schon seit PHP 7.4 mit dem sogenannten spread operator (...)
. Allerdings nur für indizierte Arrays, also Arrays mit Integer-Index:
$array = [0 => '123', 1 => '789'];
PHP 8.1 erlaubt unpacking jetzt auch mit maps-Arrays.
$array1 = ['eins' => 'one'];
$array2 = ['zwei' => 'two'];
# Alte Methode
$alle = array_merge($array1, $array2, ['drei' => 'three']);
var_dump($alle);
# Ist äquvalent zu
$alle = [...$array1, ...$array2, ...['drei' => 'three']];
var_dump($alle);
# beide geben aus:
/*
array(3) {
["eins"]=>
string(3) "one"
["zwei"]=>
string(3) "two"
["drei"]=>
string(5) "three"
}
*/
Keys von „hinteren“ Arrays überschreiben gleichnamige Keys „vorderer“ Arrays. Der +
-Operator kann diesen Prozess aber auch umkehren:
var_dump(
['eins' => 'one']
+['eins' => 'uno']
);
# array(1) {
# ["eins"]=>
# string(3) "one"
# }
var_dump([
...['eins' => 'one'],
...['eins' => 'uno']
]);
# array(1) {
# ["eins"]=>
# string(3) "uno"
# }
10. Neue Syntax für Closures
Die sogenannte first class callable syntax erlaubt konzisen Code. Bisher war ein Aufruf von Closure:fromCallable
notwendig. Jetzt gibt es eine übersichtliche Dreipunkt-Notation.
$callable = Closure::fromCallable('strtoupper');
# wird zu
$callable = strtoupper(...);
echo $callable('hostpress'); #=> HOSTPRESS
Die Syntax funktioniert für Klassenmethoden, statische Methoden und anonyme Funktionen
# Klassenmethode
$callable = $item->getHosting(...);
# Statische Methode
$callable = $item::getHosting(...);
# Anonyme Funktion
$function = function() {};
$callable = $function(...);
11. Fazit: Jetzt schon upgraden?
Na, wer hat da keine Lust, upzugraden? WordPress verlangt selbst noch eine 7er-Version zum stabilen Betrieb. Ein direktes Upgraden ist also nicht akut. Aber reizvoll machen es die vielen neuen Features von PHP 8.1 schon. Nicht alle davon werden ihre Fans haben, jedoch gefällt uns besonders, dass PHP stets Fortschritte macht und dabei mit jedem Release auch immer ein wenig schneller wird. Wir freuen uns schon auf 8.2 und 9.0.
Die Kompatibilität mit WordPress ist grundlegend gegeben, auch wenn hier an manchen Punkten noch Nachholbedarf besteht. Bei HostPress werden neue PHP-Versionen gleich nach dem Release getestet und so ist auch PHP 8.1 bereits verfügbar und kann über die Verwaltungsoberfläche mit einem Klick aktiviert werden. Generell empfiehlt sich aber, die neue Version vorab auf einer Staging-Seite zu testen.
Welches Feature gefällt dir am besten und wovon wirst du am meisten Gebrauch machen?[/vc_column_text][/vc_column][/vc_row][vc_row row_height_percent=“0″ override_padding=“yes“ h_padding=“2″ top_padding=“2″ bottom_padding=“2″ overlay_alpha=“50″ gutter_size=“3″ column_width_use_pixel=“yes“ shift_y=“0″ z_index=“0″ uncode_shortcode_id=“387697″ column_width_pixel=“1000″][vc_column width=“1/2″][vc_column_text uncode_shortcode_id=“205521″]
12. Quellen
- What’s New in PHP 8.1?
- 5 Exciting New Features in PHP 8.1
- Viele Beispiele aus der grossartigen Sammlung auf php.watch entnommen/adaptiert.
[/vc_column_text][/vc_column][vc_column width=“1/2″][uncode_index el_id=“index-708644″ loop=“size:1|order_by:date|post_type:post|by_id:55276|taxonomy_count:10″ screen_lg=“1000″ screen_md=“600″ screen_sm=“480″ gutter_size=“3″ post_items=“media|featured|onpost|original,title“ single_width=“6″ single_shape=“round“ single_overlay_opacity=“50″ single_padding=“2″ uncode_shortcode_id=“207660″][/vc_column][/vc_row]