Constructor Property Promotion, Named Arguments und mehr

Was kann PHP 8.0? Core-Entwickler Larry Garfield stellt seine Highlights vor
Keine Kommentare

Die neueste Version der beliebtesten serverseitigen Sprache des Webs wurde lange erwartet und im November des letzten Jahres veröffentlicht: PHP 8.0 hat das Licht der Welt erblickt. Larry Garfield, Core-Entwickler bei PHP, stellt uns seine favorisierten Neuerungen vor

Nach einem Jahr Entwicklungszeit wurde PHP 8.0 nun der Weltöffentlichkeit vorgestellt. Mit einer Fülle von neuen Funktionen, die mehr Leistung mit weniger Code versprechen, ist es die am meisten erwartete Version von PHP seit … nun, seit v7.4 im letzten Jahr. PHP ist aufregend, was soll ich anderes sagen?

PHP 8.0 ist vollgestopft mit neuen Funktionen: Von einem ausdrucksstärkeren Typisierungssystem über match()-Ausdrücke bis hin zu den potenziell enormen Verbesserungen bei persistenten Diensten durch die neue JIT-Erweiterung – PHP 8 hat für jeden etwas zu bieten. Es gibt jedoch drei Features, die ich besonders hervorheben möchte, da sie im Mittelpunkt der neuen Version stehen. Diese Features befanden sich alle bereits länger auf der Wunschliste, aber vor allem im Zusammenspiel ergeben sie etwas, das größer ist als die Summe ihrer Teile.

Constructor Property Promotion

Das erste Feature ist die Constructor Property Promotion. Constructor Promotion ist nur syntaktischer Zucker, um das Schreiben von Konstruktoren und Objekteigenschaften weniger repetitiv zu machen. Ein Beispiel ist die Klasse, die in Listing 1 zu sehen ist. Dieser Code kann nun wie in Listing 2 dargestellt zusammengefasst werden.

 
<?php

class MailMessage
{
  private string $to;
  private string $subject;
  private string $from;
  private string $body;
  private array $cc;
  private array $bcc;
  private string $attachmentPath;

  public function __construct(
    string $to;
    string $subject;
    string $from;
    string $body;
    array $cc = [];
    array $bcc = [];
    string ?$attachmentPath = null;
  ) {
    $this->to = $to;
    $this->subject = $subject;
    $this->from = $from;
    $this->body = $body;
    $this->cc = $cc;
    $this->bcc = $bcc;
    $this->attachmentPath = $attachmentPath;
  }
}
 
<?php

Class MailMessage
{
  public function __construct(
    private string $to,
    private string $subject,
    private string $from,
    private string $body,
    private array $cc = [],
    private array $bcc = [],
    private ?string $attachmentPath = null,
  ) {}
}

Wir sehen das gleiche Ergebnis bei einem Viertel des geschriebenen Codes. Und natürlich können Sie immer noch Dinge wie Non-promoted Properties und Parameter oder einen Constructor Body für zusätzliches Verhalten verwenden. Das mag nur wie eine kleine Änderung erscheinen, ist aber in Wirklichkeit ziemlich mächtig. Nicht nur, weil es unnötig ausführlichen Code reduziert (was großartig ist), sondern weil es bestimmte Ansätze einfacher macht. Insbesondere die Definition eines struct-ähnlichen Objekts (also eines, das nur öffentliche Eigenschaften enthält, die vom Konstruktor gemappt werden) ist vier Mal einfacher zu schreiben.

Heutzutage werden viele Entwickler und Entwicklerinnen standardmäßig assoziative Arrays für Quick-and-dirty-Strukturen verwenden. Das ist weniger selbstdokumentierend, verbraucht mehr Speicher, ist schwieriger zu benutzen und ist in jeder Hinsicht schlechter als die Definition einer richtigen Klasse – außer, dass viele das Erstellen einer Klasse für diesen Zweck als zu viel Arbeit empfinden. Nun, das Definieren einer Klasse ist nicht zu viel Arbeit und kann die Qualität und Effizienz einer Codebasis erheblich verbessern.

International PHP Conference

Frameworkless – the new black?

by Carsten Windler (KW-Commerce GmbH)

Getting started with PHP-FFI

by Thomas Bley (Bringmeister GmbH)

JSON-Schema von 0 auf 100

by Ingo Walther (Electronic Minds GmbH)

IT Security Camp 2021

Von der Cloud über DevSecOps bis hin zu Datenschutzproblem von WhatsApp

Christian Schneider spricht im Interview über aktuelle Security-Trends. Welche Themen rücken besonders heute stark in den Security-Fokus, warum alles rund um die Cloud immer mehr an Bedeutung gewinnt, welche Aspekte in der Cyberabwehr effektiv sind u.v.m.

IT-Security Experte, Christian Schneider

Christian ist als freiberuflicher White Hat Hacker, Trainer und Security-Coach tätig. Als Softwareentwickler mit mittlerweile 20 Jahren Erfahrung, fand er 2005 seinen Themenschwerpunkt im Bereich IT-Security.

Attribute

Das zweite wichtige Feature sind Attribute. Sie bieten die Möglichkeit, eine Klasse, Funktion, Eigenschaft oder ein Argument mit Metadaten zu versehen, die zur Laufzeit untersucht werden können – und zwar mit voller Unterstützung der Sprache. Diese Funktionalität stand bisher nur über Bibliotheken von Drittanbietern und über das benutzerdefinierte Parsen von Kommentarblöcken zur Verfügung, jetzt ist sie endlich als erstklassiger Bestandteil der Sprache verfügbar. Attribute können entweder bloße Strings sein oder auf Klassen abgebildet werden, wobei Letzteres in der Regel vorzuziehen ist (aus den gleichen Gründen, aus denen Klassen unstrukturierten Arrays vorzuziehen sind).

Obwohl Attribute an sich keine besondere Funktionalität haben, ist es einfach genug, sie im User-Space hinzuzufügen. Um zu definieren, dass die Betreffzeile einer E-Mail-Nachricht nur reinen Text enthält und auf 120 Zeichen begrenzt ist, könnten Sie zum Beispiel ein Attribut definieren (Listing 3).

 
<?php

#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_PARAMETER)]
class PlainText
{
  public function __construct(private ?int $length = null) {}

  public function valid(string $str): bool
  {
    return (strlen($str) <= $this->length) && strip_tags($str) === $str;
  }
}

Wir sehen hier die Constructor Promotion bei der Arbeit. Attribute sind ein perfektes Beispiel für Struct Classes, daher ist die Constructor Promotion eine natürliche Anpassung. Wir kennzeichnen das Attribut auch als nur für Eigenschaften und Parameter gültig, da es für eine Klasse oder Funktion keinen logischen Sinn ergeben würde. Jetzt kann die Eigenschaft „Betreffzeile“ mit einem Tag versehen werden (Listing 4).

 
<?php

Class MailMessage
{
  public function __construct(
    private string $to,
    #[PlainText(120)]
    private string $subject,
    private string $from,
    private string $body,
    private array $cc = [],
    private array $bcc = [],
    private ?string $attachmentPath = null,
  ) {}
}

Nun können wir zu jeder Zeit ein MailMessage-Objekt validieren, wie in Listing 5 geschehen.

 
<?php

$attribs = new \ReflectionObject($addr)
  ->getProperty('subject')
  ->getAttributes(PlainText::class);
if (! $attribs[0]->valid($mail->subject)) {
  throw new SomethingIsVeryWrongException();
}

In der Praxis würden man sich etwas Robusteres wünschen, aber lassen Sie es uns für den Moment so einfach wie möglich halten. All das geschieht mit nativem PHP-Code; es werden keine Bibliotheken von Drittanbietern benötigt. Das bedeutet, dass die Attributsyntax auch für Linters zur Verfügung steht, damit Ihre IDE sie farblich kodieren, typisieren oder autovervollständigen kann. Und das ist nur die Spitze des Eisbergs dessen, was an Metaprogrammierung jetzt nativ in PHP verfügbar ist.

Named Arguments

Der dritte und letzte Teil des großen PHP-8.0-Dreigestirns sind Named Arguments. Sie verkörpern genau das, was ihre Bezeichnung bereits aussagt. Anstatt eine Funktion mit Positionsargumenten aufzurufen, kann nun jede Funktion oder Methode mit benannten Parametern aufgerufen werden, in beliebiger Reihenfolge:

<?php
$found = in_array(needle: 'a', haystack: $arr);

Während Named Parameter in fast jeder Situation verwendet werden können, um die Lesbarkeit zu verbessern (insbesondere, wenn die Parameter nicht sofort aus dem Kontext ersichtlich sind), ist einer ihrer wichtigsten Anwendungsfälle der Aufruf von Konstruktoren.

 
<?php

$mail = new MailMessage(
  subject: 'Write more blog posts about PHP!',
  body: 'PHP is awesome and we should have more articles about it',
  to: 'Larry Garfield',
  from: 'Robert Douglas',
  attachmentPath: '/path/to/some/file',
);

Beachten Sie, dass die Argumente in Listing 6 nicht in der deklarierten Reihenfolge stehen – und das ist auch Ordnung. Wir lassen auch einige optionale Argumente ganz weg, da wir sie nicht benötigen.

All together now!

Constructor Property Promotion, Attribute und Named Arguments sind alle für sich genommen bereits wertvolle Ergänzungen. Ihre Kombination ist jedoch der Punkt, an dem PHP 8.0 wirklich glänzt und es die Art und Weise, wie wir PHP-Code schreiben, für die nächsten Jahre verändern wird. Lassen Sie uns als Beispiel echten Code aus meiner PSR-14-Event-Dispatcher-Implementierung, Tukio [1], betrachten. Er definiert seine eigenen Attribute (Listing 7).

 
<?php

namespace Crell\Tukio;

use \Attribute;

#[Attribute(Attribute::TARGET_FUNCTION | Attribute::TARGET_METHOD)]
class Listener implements ListenerAttribute
{
  public function __construct(
    public ?string $id = null,
    public ?string $type = null,
  ) {}
}

#[Attribute(Attribute::TARGET_FUNCTION | Attribute::TARGET_METHOD)]
class ListenerBefore implements ListenerAttribute
{
  public function __construct(
    public string $before,
    public ?string $id = null,
    public ?string $type = null,
  ) {}
}

#[Attribute(Attribute::TARGET_FUNCTION | Attribute::TARGET_METHOD)]
class ListenerPriority implements ListenerAttribute
{
  public function __construct(
    public ?int $priority,
    public ?string $id = null,
    public ?string $type = null,
  ) {}
}

Sie alle werden einfachheitshalber über Constructor Promotion definiert. Diese Attribute können dann Listener, entweder Funktionen oder Methoden, ausstatten, um zu definieren, wie sie registriert werden. In den meisten Fällen können Sie eine benutzerdefinierte ID angeben:

<?php
#[Listener('mine')]
function my_listener(MyEvent $event): void
{
// ...
}

Insbesondere bei der Verwendung von Subscriber-Klassen (eine Klasse, die eine Reihe von Listenern enthält) können Sie jedoch beliebige davon mischen und anpassen. Und viele von ihnen sind als Named Arguments einfacher zu verwenden (Listing 8).

 
<?php

class MockAttributedSubscriber
{
  #[Listener('a')]
  public function onA(CollectingEvent $event) : void { ... }

  #[ListenerPriority(priority: 5, id: 'this_listener')]
  public function onB(CollectingEvent $event) : void { ... }

  #[ListenerBefore(id: 'listener_c', before: 'a')]
  public function onC(CollectingEvent $event) : void { ... }

  #[ListenerAfter(after: 'a', id: 'extra_listener')]
  public function onD(CollectingEvent $event) : void { ... }

  #[Listener]
  public function onG(RareEvent $event) : void { ... }
}

Probieren Sie es heute aus

Natürlich gibt es in PHP 8.0 einige Änderungen [2], die Probleme für älteren Code mit sich bringen könnten. Wie bei jeder PHP-Version sollten Sie Ihren Code testen, bevor Sie Ihre Version einfach aktualisieren. Und das Testen von PHP 8.0 auf https://platform.sh könnte nicht einfacher sein. Legen Sie zunächst einen neuen Branch in Ihrem Repository an, aktualisieren Sie dann Ihre Datei .platform.app.yaml in diesem Zweig und ändern Sie den Key-Type in:

yaml
type: php:8.0

Git Commit und Deploy. Dieser Branch läuft jetzt unter PHP 8.0. Probieren Sie ihn aus, führen Sie Integrationstests durch, überprüfen Sie ihn stichprobenartig und schauen Sie, ob etwas aktualisiert werden muss. Sobald Sie alle notwendigen Änderungen vorgenommen haben, führen Sie diesen Branch wieder mit dem Master zusammen. Herzlichen Glückwunsch, Sie verwenden jetzt PHP 8.0 in der Produktion. Auch wenn Sie noch nicht bereit sind, auf PHP 8.0 zu aktualisieren, sollten Sie sich trotzdem einen Plan dafür machen.

Der Securitysupport für PHP 7.2 läuft am 30. November aus, und 7.3 geht für ein weiteres Jahr in einen reinen Sicherheitsmodus über. Wenn Sie noch mit älteren PHP-Versionen arbeiten, verpassen Sie nicht nur die Leistungsverbesserungen und neuen Funktionen, sondern verwenden möglicherweise auch noch unsichere PHP-Versionen. Machen Sie Versionsupgrades zu einem regelmäßigen Teil Ihres Wartungszyklus und es wird nicht wirklich eine Last sein, sondern ein Vergnügen, auf das Sie sich freuen können. Mit jedem Upgrade erhalten Sie all die neuen lustigen Spielzeuge, mit denen Sie spielen können.

Links & Literatur


[1] https://github.com/Crell/Tukio
[2] https://platform.sh/blog/2020/php-80-feature-focus-language-tightening/

Unsere Redaktion empfiehlt:

Relevante Beiträge

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