Dieser Artikel ist übersetzt, Originaladresse: https://stitcher.io/blog/php-81-readonly-properties
PHP 8.1: Schreibgeschützte Eigenschaften
Seit vielen Jahren verwende ich PHP dazu Das Schreiben von Datenübertragungsobjekten und -werten wird sehr einfach. Nehmen Sie das Beispiel eines DTO in PHP 5.6:
class BlogData { /** @var string */ private $title; /** @var Status */ private $status; /** @var \DateTimeImmutable|null */ private $publishedAt; /** * @param string $title * @param Status $status * @param \DateTimeImmutable|null $publishedAt */ public function __construct( $title, $status, $publishedAt = null ) { $this->title = $title; $this->status = $status; $this->publishedAt = $publishedAt; } /** * @return string */ public function getTitle() { return $this->title; } /** * @return Status */ public function getStatus() { return $this->status; } /** * @return \DateTimeImmutable|null */ public function getPublishedAt() { return $this->publishedAt; } }
und vergleichen Sie es mit dem Äquivalent in PHP 8.0:
class BlogData { public function __construct( private string $title, private Status $status, private ?DateTimeImmutable $publishedAt = null, ) {} public function getTitle(): string { return $this->title; } public function getStatus(): Status { return $this->status; } public function getPublishedAt(): ?DateTimeImmutable { return $this->publishedAt; } }
Es ist ganz anders, obwohl ich denke, dass es immer noch ein großes Problem gibt: all diese Getter. Ich persönlich verwende sie seit PHP 8.0 und seinen verbesserten Eigenschaften nicht mehr. Ich verwende einfach lieber öffentliche Eigenschaften, anstatt Getter hinzuzufügen:
class BlogData { public function __construct( public string $title, public Status $status, public ?DateTimeImmutable $publishedAt = null, ) {} }
Objektorientierte Puristen mögen diesen Ansatz nicht: Der interne Zustand eines Objekts sollte nicht direkt offengelegt werden und kann auf keinen Fall von außen geändert werden.
In unserem Projekt bei Spatie haben wir eine interne Styleguide-Regel, die besagt, dass DTOs und VOs mit öffentlichen Eigenschaften nicht extern geändert werden sollten; eine Praxis, die gut zu funktionieren scheint und die wir schon seit langem anwenden. Es sind keine Probleme aufgetreten.
Allerdings stimme ich zu, dass es besser wäre, wenn die Sprache sicherstellen würde, dass öffentliche Eigenschaften überhaupt nicht außer Kraft gesetzt werden. Nun, PHP 8.1 hat all diese Probleme durch die Einführung des readonly-Schlüsselworts gelöst:
class BlogData { public function __construct( public readonly string $title, public readonly Status $status, public readonly ?DateTimeImmutable $publishedAt = null, ) {} }
Dieses Schlüsselwort macht im Grunde das, was sein Name vermuten lässt: Sobald eine Eigenschaft festgelegt ist, kann sie nicht mehr überschrieben werden:
$blog = new BlogData( title: 'PHP 8.1: readonly properties', status: Status::PUBLISHED, publishedAt: now() ); $blog->title = 'Another title'; Error: Cannot modify readonly property BlogData::$title
Zu wissen, dass, wenn ein Objekt erstellt wird, Es kann sich nicht noch einmal ändern, bietet ein gewisses Maß an Sicherheit und Sicherheit beim Schreiben von Code: Eine Reihe unvorhergesehener Datenänderungen kann einfach nicht noch einmal passieren.
Natürlich möchten Sie trotzdem die Möglichkeit haben, die Daten in das neue Objekt zu kopieren und dabei möglicherweise einige Eigenschaften zu ändern. Wir werden später in diesem Artikel besprechen, wie dies mithilfe schreibgeschützter Eigenschaften funktioniert. Schauen wir sie uns zunächst genauer an.
Möchten Sie mehr über PHP 8.1 erfahren? Es gibt einen Pfad zu PHP 8.1. In den nächsten 10 Tagen erhalten Sie täglich eine E-Mail über eine neue und bestehende Funktion von PHP 8.1. Anschließend werden Sie automatisch abgemeldet, sodass Sie keinen Spam oder Folge-E-Mails erhalten. Jetzt abonnieren!
#Nur Eingabeeigenschaften
Schreibgeschützte Eigenschaften können nur in Kombination mit typisierten Eigenschaften verwendet werden:
class BlogData { public readonly string $title; public readonly $mixed; }
Sie können jedoch gemischt als Typhinweis verwenden:
class BlogData { public readonly string $title; public readonly mixed $mixed; }
Der Grund für diese Einschränkung ist das Weglassen von Eigenschaftstyp, null PHP legt den Wert der Eigenschaft automatisch fest, wenn im Konstruktor kein expliziter Wert angegeben wird. Dieses Verhalten kann in Kombination mit readonly zu unnötiger Verwirrung führen.
#Normale Eigenschaften und hochgestufte Eigenschaften
Sie haben Beispiele für beides gesehen: Schreibgeschützt kann für normale Eigenschaften und hochgestufte Eigenschaften hinzugefügt werden:
class BlogData { public readonly string $title; public function __construct( public readonly Status $status, ) {} }
#Kein Standardwert
Schreibgeschützte Eigenschaften können keine Standardwerte haben:
class BlogData { public readonly string $title = 'Readonly properties'; }
Das heißt, es sei denn, es handelt sich um heraufgestufte Eigenschaften:
class BlogData { public function __construct( public readonly string $title = 'Readonly properties', ) {} }
Es ist erlaubt, Eigenschaften heraufzustufen, da der Standardwert einer heraufgestuften Eigenschaft nicht als Standardwert der Klasseneigenschaft verwendet wird, sondern nur für die Parameter des Konstruktors gilt . Hinter den Kulissen wird der obige Code wie folgt übersetzt:
class BlogData { public readonly string $title; public function __construct( string $title = 'Readonly properties', ) { $this->title = $title; } }
Sie können sehen, dass der tatsächlichen Eigenschaft kein Standardwert zugewiesen ist. Der Grund, warum Standardwerte für schreibgeschützte Eigenschaften nicht zulässig sind, liegt übrigens darin, dass sie sich nicht von Konstanten dieser Form unterscheiden.
#legacy
Während der Vererbung sind keine Änderungen am Readonly-Flag erlaubt:
class Foo { public readonly int $prop; } class Bar extends Foo { public int $prop; }
Diese Regel gilt in beide Richtungen: Das Readonly-Flag darf während der Vererbung nicht hinzugefügt oder entfernt werden.
#Unsetting ist nicht zulässig
Sobald eine schreibgeschützte Eigenschaft festgelegt ist, können Sie sie nicht mehr ändern oder gar nicht mehr festlegen:
$foo = new Foo('value'); unset($foo->prop);
#Reflection
Es gibt eine neue Methode sowie ein Flag . ReflectionProperty::isReadOnly()ReflectionProperty::IS_READONLY
#Clone
Wenn Sie also schreibgeschützte Eigenschaften nicht ändern und nicht deaktivieren können, wie erstellen Sie dann eine Kopie eines DTO oder VO und einige seiner Daten ändern? Sie können sie nicht klonen, da Sie ihre Werte nicht überschreiben können. Es gab tatsächlich die Idee, mit einem Konstrukt zu klonen, das dieses Verhalten in Zukunft ermöglichen würde, aber das würde unser Problem jetzt nicht lösen.
Nun, wenn Sie sich auf ein wenig Reflexionsmagie verlassen, können Sie ein Objekt mit einer geänderten schreibgeschützten Eigenschaft kopieren. Indem Sie ein Objekt erstellen, ohne seinen Konstruktor aufzurufen (dies kann mithilfe von Reflektion erfolgen), und dann jede Eigenschaft manuell kopieren – manchmal auch ihren Wert überschreiben – können Sie ein Objekt tatsächlich „klonen“ und seine schreibgeschützten Eigenschaften ändern.
Ich habe dafür ein kleines Paket zusammengestellt und es sieht so aus:
class BlogData { use Cloneable; public function __construct( public readonly string $title, ) {} } $dataA = new BlogData('Title'); $dataB = $dataA->with(title: 'Another title');
Ich habe tatsächlich einen speziellen Blog-Beitrag geschrieben, in dem ich die Mechanismen dahinter erkläre, die du hier lesen kannst.
Das ist also alles über schreibgeschützte Eigenschaften. Ich denke, sie sind eine großartige Funktion, wenn Sie an einem Projekt arbeiten, das viele DTOs und VOs verwendet und von Ihnen eine sorgfältige Verwaltung des Datenflusses im gesamten Code erfordert. In dieser Hinsicht helfen unveränderliche Objekte mit schreibgeschützten Eigenschaften sehr.
Das obige ist der detaillierte Inhalt vonEine ausführliche Erklärung der neuen Funktionen von PHP8.1: schreibgeschützte Eigenschaften schreibgeschützte Eigenschaften. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!