Heim >Backend-Entwicklung >PHP-Tutorial >Erstellen von streng typisierten Arrays und Sammlungen in PHP
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!
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:
<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.
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.
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>
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.
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.
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
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.
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.
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!