Heim >Backend-Entwicklung >PHP-Tutorial >Erstellen von streng typisierten Arrays und Sammlungen in PHP

Erstellen von streng typisierten Arrays und Sammlungen in PHP

Christopher Nolan
Christopher NolanOriginal
2025-02-10 11:20:11136Durchsuche

Erstellen von streng typisierten Arrays und Sammlungen in PHP

Key Takeaways

  • Php 5.6 führte die Fähigkeit ein, typisierte Arrays mit dem… Token zu erstellen, was darauf hinweist, dass eine Funktion oder Methode eine variable Argumente akzeptiert. Diese Funktion kann mit Typ -Hinweisen kombiniert werden, um sicherzustellen, dass nur bestimmte Arten von Objekten in einem Array akzeptiert werden.
  • Eine Einschränkung dieses Merkmals besteht darin, dass nur ein typisiertes Array pro Methode definiert werden kann. Um dies zu überwinden, können typisierte Arrays in „Sammelklassen“ injiziert werden, was auch spezifischere Rückgabetypen als „Array“ bei GET -Methoden ermöglicht.
  • Wertobjekte können zur benutzerdefinierten Validierung verwendet werden. Beispielsweise könnte ein Bewertungswertobjekt mit Einschränkungen erstellt werden, um sicherzustellen, dass eine Bewertung immer zwischen 0 und 5 liegt. Dies bietet eine zusätzliche Validierung einzelner Sammlungsmitglieder, ohne jedes injizierte Objekt überschleifen zu müssen.
  • streng typisierte Arrays und Sammlungen haben mehrere Vorteile. Sie bieten eine einfache Typvalidierung an einem Ort, stellen sicher, dass die Werte beim Bauwesen immer validiert wurden, die Hinzufügung einer benutzerdefinierten Logik pro Sammlung ermöglichen und die Wahrscheinlichkeit, Argumente in Methodensignaturen zu vermischen
  • Während es möglich ist, Methoden hinzuzufügen, um Änderungen zu den Werten von Sammlungen und Wertobjekten nach der ersten Konstruktion zu erleichtern, ist es effizienter, sie unveränderlich zu halten und sie in ihre primitiven Typen umzuwandeln, wenn Änderungen vorgenommen werden müssen. Nach Änderungen können die Sammlungen oder Wertobjekte mit den aktualisierten Werten rekonstruiert werden, die dann erneut validiert werden.

Dieser Beitrag erschien zum ersten Mal auf Medium und wurde hier mit Erlaubnis des Autors erneut veröffentlicht. Wir ermutigen Sie, Bert auf Medium zu folgen und ihm dort einige Vorlieben zu geben!


Eine der in Php 5.6 angekündigten Sprachmerkmale war die Hinzufügung des ... Tokens, um zu bezeichnen, dass eine Funktion oder Methode eine variable Länge von Argumenten akzeptiert.

etwas, das ich selten erwähnt habe, ist, dass es möglich ist, diese Funktion mit Typ -Tipps zu kombinieren, um im Wesentlichen typisierte Arrays zu erstellen.

Zum Beispiel könnten wir eine Filmklasse mit einer Methode haben, um ein Array von Luftdaten festzulegen, die nur DateTimeMimmable -Objekte akzeptieren:

<span><span><?php
</span></span><span>
</span><span><span>class Movie {  
</span></span><span>  <span>private $dates = [];
</span></span><span>
</span><span>  <span>public function setAirDates(\DateTimeImmutable ...$dates) {
</span></span><span>    <span>$this->dates = $dates;
</span></span><span>  <span>}
</span></span><span>
</span><span>  <span>public function getAirDates() {
</span></span><span>    <span>return $this->dates;
</span></span><span>  <span>}
</span></span><span><span>}
</span></span>
Wir können jetzt eine variable Anzahl separater DateTimeMimmable -Objekte an die Methode setAirdates () übergeben:

<span><span><?php
</span></span><span>
</span><span><span>$movie = new Movie();
</span></span><span>
</span><span><span>$movie->setAirDates(
</span></span><span>  <span><span>\DateTimeImmutable</span>::createFromFormat('Y-m-d', '2017-01-28'),
</span></span><span>  <span><span>\DateTimeImmutable</span>::createFromFormat('Y-m-d', '2017-02-22')
</span></span><span><span>);
</span></span>
Wenn wir etwas anderes als eine datetimeimmimmige übergeben würden, würde beispielsweise ein fataler Fehler geworfen:

Erstellen von streng typisierten Arrays und Sammlungen in PHP

Wenn wir stattdessen bereits eine Reihe von DateTimeMimmable -Objekten hatten, die wir an setArdates () übergeben wollten, konnten wir das ... Token erneut verwenden, aber dieses Mal, um sie auszupacken:

<span><span><?php
</span></span><span>
</span><span><span>$dates = [
</span></span><span>  <span><span>\DateTimeImmutable</span>::createFromFormat('Y-m-d', '2017-01-28'),
</span></span><span>  <span><span>\DateTimeImmutable</span>::createFromFormat('Y-m-d', '2017-02-22'),
</span></span><span><span>];
</span></span><span>
</span><span><span>$movie = new Movie();
</span></span><span><span>$movie->setAirDates(...$dates);
</span></span>
Wenn das Array einen Wert enthalten würde, der nicht vom erwarteten Typ ist, würden wir immer noch den zuvor genannten tödlichen Fehler erhalten.

Zusätzlich können wir Skalartypen ab Php 7 verwenden. Zum Beispiel können wir eine Methode hinzufügen, um eine Liste von Bewertungen als Floats in unserer Filmklasse festzulegen:

<span><span><?php
</span></span><span>
</span><span><span>class Movie {  
</span></span><span>  <span>private $dates = [];
</span></span><span>
</span><span>  <span>public function setAirDates(\DateTimeImmutable ...$dates) {
</span></span><span>    <span>$this->dates = $dates;
</span></span><span>  <span>}
</span></span><span>
</span><span>  <span>public function getAirDates() {
</span></span><span>    <span>return $this->dates;
</span></span><span>  <span>}
</span></span><span><span>}
</span></span>

Dies stellt erneut sicher, dass die Bewertungseigenschaft immer Schwimmer enthält, ohne dass wir alle Inhalte überschreiten müssen, um sie zu validieren. Jetzt können wir also leicht einige mathematische Operationen bei Getaveragering () durchführen, ohne sich um ungültige Typen sorgen zu müssen.

Probleme mit dieser Art von typisierten Arrays

Einer der Nachteile der Verwendung dieser Funktion als typisierte Arrays ist, dass wir nur ein solches Array pro Methode definieren können. Angenommen, wir wollten eine Filmklasse, die eine Liste von Luftdaten zusammen mit einer Liste von Bewertungen im Konstruktor erwartet, anstatt sie später über optionale Methoden festzulegen. Dies wäre mit der oben verwendeten Methode unmöglich.

Ein weiteres Problem ist, dass bei der Verwendung von Php 7 die Rückgabetypen unserer Get () -Methoden immer noch „Array“ sein müssten, was oft zu generisch ist.

Lösung: Sammlungsklassen

Um beide Probleme zu beheben, können wir einfach unsere typisierten Arrays in sogenannte „Sammlungsklassen“ injizieren. Dies verbessert auch unsere Bedenken Trennung, da wir nun die Berechnungsmethode für die durchschnittliche Bewertung auf die relevante Sammelklasse verschieben können:

<span><span><?php
</span></span><span>
</span><span><span>$movie = new Movie();
</span></span><span>
</span><span><span>$movie->setAirDates(
</span></span><span>  <span><span>\DateTimeImmutable</span>::createFromFormat('Y-m-d', '2017-01-28'),
</span></span><span>  <span><span>\DateTimeImmutable</span>::createFromFormat('Y-m-d', '2017-02-22')
</span></span><span><span>);
</span></span>

Beachten Sie, wie wir noch eine Liste typisierter Argumente mit einer variablen Länge in unserem Konstruktor verwenden, was uns die Mühe spart, über jede Bewertung zu schleifen, um ihren Typ zu überprüfen.

Wenn wir die Möglichkeit haben möchten, diese Sammelklasse in Foreach -Loops zu verwenden, müssten wir einfach die Iteratoraggregate -Schnittstelle implementieren:

<span><span><?php
</span></span><span>
</span><span><span>$dates = [
</span></span><span>  <span><span>\DateTimeImmutable</span>::createFromFormat('Y-m-d', '2017-01-28'),
</span></span><span>  <span><span>\DateTimeImmutable</span>::createFromFormat('Y-m-d', '2017-02-22'),
</span></span><span><span>];
</span></span><span>
</span><span><span>$movie = new Movie();
</span></span><span><span>$movie->setAirDates(...$dates);
</span></span>

Wenn wir weitermachen, können wir auch eine Sammlung für unsere Liste der Luftdaten erstellen:

<span><span><?php
</span></span><span>
</span><span><span>declare(strict_types=1);
</span></span><span>
</span><span><span>class Movie {
</span></span><span>  <span>private $dates = [];
</span></span><span>  <span>private $ratings = [];
</span></span><span>
</span><span>  <span>public function setAirDates(\DateTimeImmutable ...$dates) { /* ... */ }
</span></span><span>  <span>public function getAirDates() : array { /* ... */ }
</span></span><span>
</span><span>  <span>public function setRatings(float ...$ratings) {
</span></span><span>    <span>$this->ratings = $ratings;
</span></span><span>  <span>}
</span></span><span>
</span><span>  <span>public function getAverageRating() : float {
</span></span><span>    <span>if (empty($this->ratings)) {
</span></span><span>      <span>return 0;
</span></span><span>    <span>}
</span></span><span>
</span><span>    <span>$total = 0;
</span></span><span>
</span><span>    <span>foreach ($this->ratings as $rating) {
</span></span><span>      <span>$total += $rating;
</span></span><span>    <span>}
</span></span><span>
</span><span>    <span>return $total / count($this->ratings);
</span></span><span>  <span>}
</span></span><span><span>}
</span></span>

Wenn wir alle Teile des Puzzles in der Filmklasse zusammenfügen, können wir jetzt zwei separat typisierte Sammlungen in unserem Konstruktor injizieren. Zusätzlich können wir spezifischere Rückgabetypen als „Array“ bei unseren GET -Methoden definieren:

<span><span><?php
</span></span><span>
</span><span><span>declare(strict_types=1);
</span></span><span>
</span><span><span>class Ratings {
</span></span><span>  <span>private $ratings;
</span></span><span>
</span><span>  <span>public function __construct(float ...$ratings) {
</span></span><span>    <span>$this->ratings = $ratings;
</span></span><span>  <span>}
</span></span><span>
</span><span>  <span>public function getAverage() : float {
</span></span><span>    <span>if (empty($this->ratings)) {
</span></span><span>      <span>return 0;
</span></span><span>    <span>}
</span></span><span>
</span><span>    <span>$total = 0;
</span></span><span>
</span><span>    <span>foreach ($this->ratings as $rating) {
</span></span><span>      <span>$total += $rating;
</span></span><span>    <span>}
</span></span><span>
</span><span>    <span>return $total / count($this->ratings);
</span></span><span>  <span>}
</span></span><span><span>}
</span></span>

Verwenden von Wertobjekten für die benutzerdefinierte Validierung

Wenn wir unseren Bewertungen zusätzliche Validierung hinzufügen wollten, könnten wir noch einen Schritt weiter gehen und ein Bewertungswertobjekt mit einigen benutzerdefinierten Einschränkungen definieren. Zum Beispiel könnte eine Bewertung zwischen 0 und 5 begrenzt sein:

<span><span><?php
</span></span><span>
</span><span><span>declare(strict_types=1);
</span></span><span>
</span><span><span>class Ratings implements IteratorAggregate {
</span></span><span>  <span>private $ratings;
</span></span><span>
</span><span>  <span>public function __construct(float ...$ratings) {
</span></span><span>    <span>$this->ratings = $ratings;
</span></span><span>  <span>}
</span></span><span>
</span><span>  <span>public function getAverage() : float { /* ... */ }
</span></span><span>
</span><span>  <span>public function getIterator() {
</span></span><span>     <span>return new ArrayIterator($this->ratings);
</span></span><span>  <span>}
</span></span><span><span>}
</span></span>

Zurück in unserer Kennzeichnungsklasse müssten wir nur einige geringfügige Änderungen vornehmen, um diese Wertobjekte anstelle von Floats zu verwenden:

<span><span><?php
</span></span><span>
</span><span><span>class AirDates implements IteratorAggregate {
</span></span><span>  <span>private $dates;
</span></span><span>
</span><span>  <span>public function __construct(\DateTimeImmutable ...$dates) {
</span></span><span>    <span>$this->dates = $dates;
</span></span><span>  <span>}
</span></span><span>
</span><span>  <span>public function getIterator() {
</span></span><span>     <span>return new ArrayIterator($this->airdates);
</span></span><span>  <span>}
</span></span><span><span>}
</span></span>

Auf diese Weise erhalten wir eine zusätzliche Validierung einzelner Sammlungsmitglieder, ohne dass wir jedes injizierte Objekt überschreiten müssen.

Vorteile

tippen diese separaten Sammelklassen und das Wertobjekt wie viele Arbeiten, aber sie haben mehrere Vorteile gegenüber generischen Arrays und Skalarwerten:

  • Einfache Typ Validierung an einem Ort. Wir müssen nie manuell über ein Array schauen, um die Arten unserer Sammlungsmitglieder zu validieren.

  • Wo immer wir diese Sammlungen und Wertobjekte in unserer Anwendung verwenden, wissen wir, dass ihre Werte bei der Konstruktion immer validiert wurden. Zum Beispiel wird jede Bewertung immer zwischen 0 und 5 sein;

  • Wir können einfach benutzerdefinierte Logik pro Sammlung und/oder Wertobjekt hinzufügen. Zum Beispiel die Methode von GetAverage (), die wir während unserer gesamten Anwendung wiederverwenden können;

  • Wir erhalten die Möglichkeit, mehrere typisierte Listen in eine einzelne Funktion oder Methode zu injizieren.

  • Es gibt signifikant reduzierte Wahrscheinlichkeit, Argumente in Methodensignaturen zu vermischen. Wenn wir beispielsweise sowohl eine Liste von Bewertungen als auch eine Liste von Luftdaten injizieren möchten, können sich die beiden bei der Verwendung von generischen Arrays durch einen Unfall durcheinander verwechseln.
  • Was ist mit Änderungen?

Inzwischen fragen Sie sich vielleicht, wie Sie nach der ersten Konstruktion Änderungen an den Werten Ihrer Sammlungen und Wertobjekte vornehmen können.

Während wir Methoden hinzufügen konnten, um Änderungen zu erleichtern, würde dies schnell umständlich werden, da wir die meisten Methoden auf jeder Sammlung duplizieren müssten, um den Vorteil der Typ -Hinweise zu erhalten. Beispielsweise sollte eine add () -Methode für Bewertungen nur ein Bewertungsobjekt akzeptieren, während eine add () -Methode auf Airdates nur ein datetimeMimmable -Objekt akzeptieren sollte. Dies macht die Schnittstelle und/oder die Wiederverwendung dieser Methoden sehr schwierig.

Stattdessen konnten wir einfach unsere Sammlungen und Wertobjekte unveränderlich halten und sie in ihre primitiven Typen umwandeln, wenn wir Änderungen vornehmen müssen. Nachdem wir Änderungen vorgenommen haben, können wir die erforderlichen Sammlungen oder Wertobjekte mit den aktualisierten Werten einfach neu konstruieren. Beim (re) Bauen werden alle Typen erneut validiert, zusammen mit einer zusätzlichen Validierung, die wir möglicherweise definiert haben.

Zum Beispiel könnten wir unseren Sammlungen eine einfache Methode für there () hinzufügen und Änderungen wie folgt vornehmen:

Auf diese Weise können wir auch vorhandene Array-Funktionen wie Array_filter () wiederverwenden.
<span><span><?php
</span></span><span>
</span><span><span>class Movie {  
</span></span><span>  <span>private $dates = [];
</span></span><span>
</span><span>  <span>public function setAirDates(\DateTimeImmutable ...$dates) {
</span></span><span>    <span>$this->dates = $dates;
</span></span><span>  <span>}
</span></span><span>
</span><span>  <span>public function getAirDates() {
</span></span><span>    <span>return $this->dates;
</span></span><span>  <span>}
</span></span><span><span>}
</span></span>

Wenn wir wirklich Änderungen an den Sammlungsobjekten selbst vornehmen mussten, können wir die erforderlichen Methoden auf der Grundlage von Bedarf hinzufügen, wo immer sie erforderlich sind. Denken Sie jedoch daran, dass die meisten dieser auch die Validierung der angegebenen Argumente durchführen müssen. Daher ist es schwierig, sie in allen verschiedenen Sammelklassen wiederzuverwenden.

generische Methoden wiederverwenden

Wie Sie vielleicht bemerkt haben, erhalten wir in unseren Sammelklassen immer noch eine Code -Duplikation in unseren Sammelklassen, indem wir sowohl toArray () als auch Getiterator () auf allen implementieren. Zum Glück sind diese Methoden generisch genug, um zu einer generischen Elternklasse zu wechseln, da beide einfach das injizierte Array zurückgeben:

Alles, was wir in unserer Sammelklasse übrig bleiben würden, wäre die Typ -Validierung im Konstruktor und jede optionale zusätzliche Logik, die für diese Sammlung spezifisch ist, wie folgt:
<span><span><?php
</span></span><span>
</span><span><span>$movie = new Movie();
</span></span><span>
</span><span><span>$movie->setAirDates(
</span></span><span>  <span><span>\DateTimeImmutable</span>::createFromFormat('Y-m-d', '2017-01-28'),
</span></span><span>  <span><span>\DateTimeImmutable</span>::createFromFormat('Y-m-d', '2017-02-22')
</span></span><span><span>);
</span></span>
<span><span><?php
</span></span><span>
</span><span><span>class Movie {  
</span></span><span>  <span>private $dates = [];
</span></span><span>
</span><span>  <span>public function setAirDates(\DateTimeImmutable ...$dates) {
</span></span><span>    <span>$this->dates = $dates;
</span></span><span>  <span>}
</span></span><span>
</span><span>  <span>public function getAirDates() {
</span></span><span>    <span>return $this->dates;
</span></span><span>  <span>}
</span></span><span><span>}
</span></span>

optional könnten wir unsere Sammlung endgültig machen, um zu verhindern, dass Kinderklassen mit der Eigenschaft der Werte auf eine Weise durcheinander bringen, die unsere Typ -Validierung rückgängig macht.

Schlussfolgerung

Obwohl es immer noch alles andere als perfekt ist, wurde es stetig einfacher, mit Typ Validierung in Sammlungen und Wertobjekten mit den jüngsten Veröffentlichungen von PHP zu arbeiten.

Idealerweise würden wir in einer zukünftigen Version von PHP eine Form von Generika erhalten, um die Erstellung wiederverwendbarer Sammlungsklassen weiter zu erleichtern.

Eine Funktion, die die Verwendung von Wertungsobjekten erheblich verbessern würde, wäre die Fähigkeit, ein Objekt zusätzlich zur String ein Objekt an verschiedene primitive Typen zu geben. Dies könnte leicht implementiert werden, indem zusätzliche magische Methoden hinzugefügt werden, die mit __tostring () wie __toint (), __tofloat () usw. vergleichbar sind, usw.

Zum Glück gibt es einige RFCs, um möglicherweise beide Funktionen in späteren Versionen zu implementieren, sodass die Daumen gekreuzt sind! ?

  • Generika: https://wiki.php.net/rfc/generics

  • Generische Arrays: https://wiki.php.net/rfc/generic-arrays

  • Casting -Objekt in Scalar: https://wiki.php.net/rfc/class_casting_to_scalar


Wenn Sie dieses Tutorial hilfreich gefunden haben, besuchen Sie bitte den Originalbeitrag auf Medium und geben Sie ihm einige ❤️. Wenn Sie Feedback, Fragen oder Kommentare haben, lassen Sie sie bitte unten oder als Antwort auf den ursprünglichen Beitrag.

häufig gestellte Fragen (FAQs) zum Erstellen von streng getippten Arrays und Sammlungen in PHP

Wie hoch sind die Vorteile der Verwendung von streng getippten Arrays in PHP? Dies kann besonders in größeren, komplexeren Anwendungen nützlich sein, bei denen die Datenkonsistenz von entscheidender Bedeutung ist. Durch die Durchsetzung eines bestimmten Typs für alle Elemente in einem Array können Sie potenzielle Fehler und Fehler verhindern, die aufgrund unerwarteter Datentypen auftreten können. Es macht Ihren Code auch vorhersehbarer und einfacher zu debuggen, da Sie immer die Art der Daten kennen, mit denen Sie arbeiten. unterstützt nicht streng typisierte Arrays. Sie können jedoch eine Klasse erstellen, die die Typ -Überprüfung der dem Array hinzugefügten Elemente erzwingt. Diese Klasse hätte Methoden zum Hinzufügen und Abrufen von Elementen, und diese Methoden würden den Typ des Elements überprüfen, bevor die Operation durchgeführt wird. Wenn der Typ des Elements nicht mit dem erwarteten Typ übereinstimmt, würde ein Fehler geworfen. Sie können angeben, dass eine Funktion oder Methode ein Array als Argument erwartet, indem Sie „Array“ vor dem Argumentnamen in der Funktion oder Methodeerklärung hinzufügen. Dies stellt jedoch nur sicher, dass das Argument ein Array ist, nicht dass alle Elemente im Array von einem bestimmten Typ sind.

Was ist der Unterschied zwischen locker typisierten und streng typisierten Arrays? In einem streng getippten Array müssen alle Elemente von einem bestimmten Typ sein. Wenn Sie versuchen, einem streng getippten Array ein Element eines anderen Typs hinzuzufügen, wird ein Fehler geworfen. PHP unter Verwendung der "deklar (strict_types = 1)"; Richtlinie zu Beginn Ihrer PHP -Datei. Dadurch wird die strenge Typ -Überprüfung aller Funktionsaufrufe und Rückgabeberechnungen in der Datei erzwingen. von Objekten in PHP durch Erstellen einer Klasse, die die dem Array hinzugefügten Objekte die Typ -Überprüfung erzwingt. Die Klasse hat Methoden zum Hinzufügen und Abrufen von Objekten, und diese Methoden würden den Typ des Objekts überprüfen, bevor die Operation durchgeführt wird. Die Hauptbeschränkung von streng typisierten Arrays in PHP besteht darin, dass sie zusätzlichen Code benötigen, da PHP sie nicht nativ unterstützt. Dadurch kann Ihr Code komplexer und zu warten. Darüber hinaus können streng getippte Arrays weniger flexibel sein als locker getippte Arrays, da sie keine Elemente verschiedener Typen zulassen. Sie können den Typ verwenden, der bei mehrdimensionalen Arrays in PHP angedeutet wird. Der Typ von PHP ist jedoch nur sicher, dass das Argument ein Array ist, nicht dass alle Elemente im Array (oder Sub-Arrays) von einem bestimmten Typ sind. PHP?

Wenn Sie streng eingegebene Arrays in PHP verwenden, können Sie Fehler mithilfe von Try-Catch-Blöcken verarbeiten. Wenn beim Hinzufügen eines Elements zum Array ein Fehler auftritt (z. B. wenn das Element vom falschen Typ ist), wird eine Ausnahme ausgelöst. Sie können diese Ausnahme fangen und angemessen umgehen. Funktionen. Sie müssen jedoch vorsichtig sein, da diese Funktionen die Typ -Überprüfung nicht erzwingen. Wenn Sie eine Funktion verwenden, die das Array ändert und ein Element des falschen Typs hinzufügt, kann dies zu Fehlern führen.

Das obige ist der detaillierte Inhalt vonErstellen von streng typisierten Arrays und Sammlungen in PHP. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn