Ausblick auf PHP 8: Teil 3

PHP 8.0-Features im Fokus: Weak Maps
Keine Kommentare

Das Release von PHP 8 steht kurz bevor und mit ihm eine Reihe von Verbesserungen, neuen Funktionen und die generelle Überarbeitung, um die weit verbreitete serverseitige Websprache noch besser zu machen. In dieser Serie wollen wir darauf eingehen, was Sie über PHP 8 wissen sollten.

Der Countdown zum großen Release von PHP 8 ist bereits angebrochen. Die lang erwartete neue Version enthält eine ganze Reihe von neuen Funktionen und Verbesserungen, die den Entwicklern das Leben leichter machen sollen. In dieser Serie werfen wir einen Blick auf diese Neuerungen und was sie für die Nutzer bedeuten. Im zweiten Teil beschäftigen wir uns mit den neuen Weak Maps.

Mit PHP 7.4 wurde das Konzept der Weak References eingeführt, die es ermöglichen, ein Objekt zu referenzieren, ohne seinen Referenzzähler zu erhöhen. Das ist ein wenig obskur und in der Praxis oft auch nicht sehr nützlich. Worauf wir wirklich gewartet haben, sind die Weak Maps, die mit PHP 8.0 kommen werden.

Weak Maps sind ein wenig sonderbar zu erklären, habt also bitte etwas Geduld mit mir. Wenn wir ein Objekt erstellen und es einer Variablen zuweisen, passiert normalerweise Folgendes: Das Objekt wird im Speicher erstellt, und dann wird die Variable als Verweis darauf kreiert. Stellen wir uns vor, dass die Variable nur die ID des Objekts hat, nicht das Objekt selbst. Wenn wir dem gleichen Objekt eine weitere Variable zuweisen, gibt es immer noch nur ein Objekt, aber zwei Variablen mit der ID des Objekts.

<?php

$a = new Foo();
$b = $a;

// $b and $a are now separate variables that 
// both point to a Foo object in memory somewhere.

Jedes Mal, wenn eine Variable entfernt wird, prüft PHP, ob es noch andere Variablen gibt, die auf dieses Objekt verweisen. Ist dies nicht der Fall, wird es als sicher angesehen, dieses Objekt für den Nutzer zu löschen. Dieser Vorgang wird „Garbage Collection“ genannt, und ich habe ihn hier stark vereinfacht, weil das für unsere Zwecke ausreicht.

Eine Weak Reference oder eine Weak Map ist eine Möglichkeit, eine Variable zu erstellen, die sich wie jede andere verhält, aber wenn PHP prüft, ob irgendwelche Variablen immer noch auf ein Objekt zeigen, zählen diese „schwachen“ Variablen nicht. Wenn es also immer noch drei Weak References gibt, die auf ein Objekt zeigen, aber keine normalen Variablen, wird PHP das Objekt löschen und stattdessen die verbleibenden Variablen auf Null setzen.

IT Security Summit 2020

Zero Trust – why are we having this conversation?

mit Victoria Almazova (Microsoft)

Digitaler Ersthelfer

mit Martin Wundram (DigiTrace GmbH)

Betrachten wir uns dies nun einmal in der Praxis. Angenommen, wir haben eine Reihe von Product-Objekten, die von jemand anderem in einer Art Bibliothek geschrieben wurden. Wir können sie nicht ändern, aber wir werden sie verwenden. Für jedes Product möchten Sie zusätzliche Informationen nachverfolgen, die sich nicht auf dem Originalobjekt befinden, z. B. eine Liste von Review-Objekten zu diesem Product. Eine Unterklassifizierung des Products zur Aufnahme von Rezensionen ist möglich, aber unübersichtlich. Außerdem stößt die Vererbung beim Versuch, mehrere Module miteinander zu kombinieren, häufig auf Probleme. Stattdessen erstellen wir ein separates ReviewList-Objekt, das eine Weak Map von Review-Objekten enthält, die bei Bedarf lazy geladen und nach Product getracked werden. Sobald ein Product aus dem Speicher entfernt wurde und alle Variablen, die darauf verweisen, den Scope verlassen haben, brauchen wir diese Review-Objekte nicht mehr zu behalten. Eine WeakMap fungiert in diesem Fall als selbstreinigender Cache und funktioniert ähnlich wie ArrayObject.

<?php
class ReviewList
{
    private WeakMap $cache;

    public function __construct()
    {
        $this->cache = new WeakMap();
    }

    public function getReviews(Product $prod): string
    {
        return $this->cache[$prod] ??= $this->findReviews($prod->id());
    }

    protected function findReviews(int $prodId): array
    {
        // ...
    }
}


$reviewList = new ReviewList();
$prod1 = getProduct(1);
$prod2 = getProduct(2);

$reviews_p1 = $reviewList->getReviews($prod1);
$reviews_p2 = $reviewList->getReviews($prod2);

// ...

$reviews_p1_again = $reviewList->getReviews($prod1);

unset($prod1);

In diesem Beispiel verfügt ReviewList über einen internen „Weak Cache“, in dem die Product-Objekte abgelegt sind. Wenn getReviews() aufgerufen wird und sich der gewünschte Wert bereits im Cache befindet, wird er zurückgegeben. Wenn nicht, wird er in den Speicher geladen, im WeakMap-Cache gespeichert und dann zurückgegeben. (Das ??= Bit dort ist ein null-coalesce-assign, eingeführt in PHP 7.4, und das beste Vorgehen in diesen Fällen). Später, wenn wir $reviews_p1_again erstellen, wird der Wert stattdessen im Cache gesucht.

Irgendwann in der Zukunft verwerfen wir jedoch $prod1. Im Allgemeinen wird das nicht manuell geschehen, aber die Variable wird aus dem Scope genommen und vom Garbage Collector eingesammelt werden. Da es keine normalen Verweise auf das Product-1-Objekt mehr gibt, wird der Verweis auf dieses Objekt in der $cache Weak Map automatisch entfernt. Dies führt auch dazu, dass die entsprechende Liste der Review-Objekte ebenfalls automatisch gelöscht wird. Der Speicher wird auf diese Weise geschont und es ist kein weiterer Aufwand erforderlich.

Wenn wir versuchen würden, dasselbe mit einem normalen Array zu tun, gäbe es zwei Probleme:

  1. Arrays können keine Objekte als Keys verwenden, also müsste es von der Produkt-ID oder ähnlichem abgeschrieben werden.
  2. Das heißt, der Cache wüsste nicht, dass er sich selbst beschränken müsste, wenn das Objekt, für das er ein Cache ist, vom Garbage Collector eingesammelt wird. Wir können vielleicht eine komplexe Logik mit Destruktoren, globalen Variablen und anderer schwarzer Magie implementieren, aber … bitte nicht. Die Chancen, es falsch zu machen, sind hoch, und der Grad der Komplexität, den es einführt, ist es nicht wert.

Caching-Szenarien wie diese sind wirklich der einzige starke Anwendungsfall für WeakMap, aber wenn Sie es brauchen, ist es ein großes Ersparnis für Speicher und Code.

Wieder einmal haben wir Nikita Popov für den WeakMap RFC zu danken.

In der nächsten Woche werden wir uns eine neue Funktion in PHP 8.0 ansehen, die versucht, „den Milliarden-Dollar-Fehler“ der Datenverarbeitung zu beheben.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Abonnieren
Benachrichtige mich bei
guest
0 Comments
Inline Feedbacks
View all comments
X
- Gib Deinen Standort ein -
- or -