Sollten HTTP-Anforderungs- / Antwortobjekte unveränderlich sein?

10

Ich denke, man kann mit Sicherheit sagen, dass die meisten Webanwendungen auf dem Anforderungs- / Antwortparadigma basieren. PHP hatte noch nie eine formale Abstraktion dieser Objekte. Eine Gruppe versucht dies zu ändern: https://github.com/php-fig/fig-standards/blob/master/proposed/http-message.md

In der Frage der Unveränderlichkeit wurden sie jedoch irgendwie von der Seite verfolgt. Einerseits muss das Anforderungs- / Antwortobjekt während seines Lebenszyklus im Allgemeinen nur sehr wenig geändert werden. Andererseits müssen insbesondere für das Antwortobjekt häufig HTTP-Header hinzugefügt werden.

Darüber hinaus hat sich die Unveränderlichkeit im Land der PHP nie wirklich durchgesetzt.

Welche Vorteile sehen Menschen bei der Verwendung unveränderlicher Anforderungs- / Antwortobjekte?


Angenommen, Sie geben ein JSON-Objekt zurück.

$response = new JsonResponse($item);

Schön und einfach. Es stellt sich jedoch heraus, dass es sich bei der Anforderung um eine CORS-Anforderung (Cross-Origin Resource Sharing) handelte. Der Code, der die Antwort generiert, sollte sich nicht darum kümmern, aber irgendwo stromabwärts ist ein Prozess, der die erforderlichen Access-Control-Header hinzufügt. Gibt es einen Vorteil, wenn Sie die ursprüngliche Antwort beibehalten und eine neue mit den zusätzlichen Headern erstellen? Oder ist es nur eine Frage des Programmierstils?

Das Request-Objekt ist etwas interessanter. Es beginnt genauso:

$request = new Request('incoming request information including uri and headers');

Die Anfangsinformationen sollten nicht geändert werden müssen. Wenn die Anforderung weitergeleitet wird, müssen jedoch häufig zusätzliche Verarbeitungsinformationen hinzugefügt werden. Beispielsweise haben Sie möglicherweise einen URL-Matcher, der entscheidet, welche Aktion für eine bestimmte Anforderung ausgeführt werden soll.

$request->setAttribute('action',function() {});

Die eigentliche Ausführung der Aktion liegt in der Verantwortung eines nachgeschalteten Prozesses. Sie könnten eine veränderbare RequestAttributesCollection haben, die die unveränderliche Anfrage umschließt, aber das ist in der Praxis etwas umständlich. Sie könnten auch eine Anfrage haben, die bis auf eine Attributsammlung unveränderlich ist. Ausnahmen sind ebenfalls umständlich. Erfahrungen im Umgang mit solchen Anforderungen?

Cerad
quelle
Wenn es sich nur um die ursprüngliche Anfrage / Antwort handelt, die Sie benötigen, können wir einen Klon des Objekts speichern, der im c'tor festgelegt wird und dann nie wieder berührt wird. Sie können mutieren, aber bei Bedarf trotzdem auf das Original zugreifen. Dies wäre wahrscheinlich besser gewesen, IMO.
Mpen

Antworten:

4

Welche Vorteile sehen Menschen bei der Verwendung unveränderlicher Anforderungs- / Antwortobjekte?

Ich stimme der Aussage von @ MainMa zu: " Ich bin nicht sicher, ob der geringe Vorteil der Lesbarkeit den möglichen Mangel an Flexibilität kompensiert. " Ich persönlich sehe keine praktischen und nützlichen Aspekte darin, PHP HTTP Requesttemporäre Objekte oder PHP HTTP Responsetemporäre Objekte unveränderlich zu machen

Erfahrungen im Umgang mit solchen Anforderungen?

  1. Das Microsoft- Windows Presentation FoundationFramework führt das Konzept der einfrierbaren Objekte ein . Einmal gefroren, werden solche Objekte

    • unveränderlich (Ausnahmen auslösen, wenn eine Änderung versucht wird),
    • schneller zu bedienen (Property Getter müssen keine ausgefallenen "Was ist mein Wert?" - Entscheidungen mehr treffen),
    • verbraucht weniger Speicher (interne Hilfsdatenstrukturen und Caches usw. können auf ihre zeit- und platzsparendste Darstellung reduziert werden)
    • und teilbar

    Obwohl es als GUI-Geschwindigkeitsoptimierung verwendet wird, ist das Konzept selbst auch anderswo anwendbar, einschließlich seiner Vorteile

  2. Nancy("Leichtes, zeremonielles Framework zum Erstellen von HTTP-basierten Diensten auf .Net und Mono") beschreibt den Vorteil der Unveränderlichkeit in einem der Commit-Kommentare als

    ... wir können davon ausgehen, dass unsere Caches unveränderlich sind, wenn sie ausgeschaltet sind, was bedeutet, dass wir keine Sperren haben, die eine schnellere Leistung bieten (obwohl der Treffer nicht massiv ist) ...

    Ich habe keine andere bemerkenswerte Kommentare über Unveränderlichkeit finden, aber der Nutzen von wieder verwendbaren, zwischenspeicherbar Antwortobjekte können anwenden PHPund

Das Obige mag wie Antworten außerhalb des Themas aussehen, aber mir ist nichts anderes bekannt, und deshalb denke ich, dass die Unveränderlichkeitsanforderung ein künstliches Problem ist und eher eine Frage der Präferenz oder des Codierungsstils usw.

xmojmr
quelle
1
Vielen Dank. Beide Antworten waren informativ. Ich habe mich entschlossen, Ihre zu akzeptieren, weil der Gedanke, Objekte einzufrieren, mein Denken klarer machte. Ein unveränderliches eingefrorenes Antwortobjekt wird erstellt, da es kurz vor dem Senden des Objekts geklont und nicht eingefroren wird. Bündel von lieferungsorientierten Headern (Caches, Cors usw.) können hinzugefügt werden. Das Objekt kann dann eingefroren und auf dem Weg gesendet werden.
Cerad
7

Unveränderliche Objekte haben im Allgemeinen mehrere Vorteile.

  • Das wichtigste ist, wie einfach es ist, unveränderliche Objekte in parallel ausgeführtem Code zu verwenden. Dies erklärt auch, warum "Unveränderlichkeit im Land von PHP nie wirklich Einzug gehalten hat" .

  • Zustandskonsistenz ist leichter zu erreichen.

  • Objekte sind einfach und natürlicher zu bearbeiten.

Das Wesentliche ist, wie stark sich das Objekt während seiner Lebensdauer ändern sollte. Für jede Änderung an einem unveränderlichen Objekt muss eine zusätzliche Instanz erstellt werden, die in Bezug auf den Speicher (und wahrscheinlich auch die CPU-Zyklen) schnell zu teuer sein kann. Dies ist auch der Grund, warum die meisten Programmiersprachen, in denen stringunveränderlich ist, eine andere Klasse für veränderbare Zeichenfolgen haben, z. B. StringBuilderin C #, um auf Situationen zu reagieren, in denen Zeichenfolgen aus vielen kleinen Teilen verkettet werden und jeder Teil dynamisch hinzugefügt wird.

In einer clientseitigen Bibliothek (Senden einer HTTP-Anforderung und Empfangen einer Antwort) ist es sinnvoll, HTTP-Anforderungen und -Antworten unveränderlich zu machen: Während einige Anforderungen mit einer fließenden Schnittstelle erstellt werden können, ist dies nicht die Hauptverwendung. Die Antwort wird sowieso nicht geändert, daher ist Unveränderlichkeit sinnvoll.

In einer serverseitigen Bibliothek (Empfangen einer HTTP-Anfrage und Senden einer Antwort) bin ich mir nicht sicher, ob die Antwort unveränderlich sein kann. Die Daten selbst können ein Stream sein (der für einige Personen - siehe unten - die Änderung des Antwortobjekts erzwingt), und die Header selbst können während der Ausführung des Skripts "on the fly" hinzugefügt werden, bis die Antwort beginnt an den Kunden gesendet werden.

In beiden Fällen bin ich mir nicht sicher, ob der geringfügige Vorteil der Lesbarkeit den möglichen Mangel an Flexibilität kompensiert, da keine parallele Ausführung erfolgt.

Lesen Sie auch einen vollständigeren Artikel von Evert Pot über PSR-7 . Der Artikel erklärt unter anderem, dass einer der Fälle, in denen eine solche Unveränderlichkeit problematisch ist, lange Antworten sind, die gestreamt werden sollten . Persönlich verstehe ich den Punkt nicht: IMHO verbietet nichts einem unveränderlichen Objekt, einen Stream zu enthalten (zum Beispiel kann ein FileReaderObjekt unveränderlich sein, selbst wenn es eine Datei liest, die sich im Laufe der Zeit ändern kann). Das Flask-Framework von Python verwendet einen anderen Ansatz, wenn es um große Antworten (oder Antworten, deren Generierung einige Zeit in Anspruch nimmt) geht, indem ein Iterator zurückgegeben wird.

Arseni Mourzenko
quelle
1
Ein erwähnenswerter Vorteil von IMO ist, dass Sie sich bei unveränderlichen Objekten nie fragen müssen, ob Sie mit einer privaten Kopie arbeiten. Sie können diese frei ändern oder eine Referenz eines anderen Objekts, bei der sich Änderungen auf andere Objekte auswirken können.
Philipp
@Philipp: IMHO, einer der größten Mängel in Java.NET ist das Fehlen einer Konvention zur Unterscheidung zwischen Methoden, die Verweise auf neue Objekte zurückgeben, die der Aufrufer nach Belieben ändern kann, und solchen, die Verweise zurückgeben, die an interne Objekte angehängt sind oder diese kapseln Zustand, der geändert werden kann, um diesen Zustand zu manipulieren, und solche, die Verweise auf Objekte zurückgeben, die an den internen Zustand angehängt werden können oder können. Es ist nicht möglich, robusten und effizienten Code zu schreiben, ohne zu wissen, welche Arten von Referenzen zurückgegeben werden sollen, aber es gibt keine Konvention, die darauf hinweist.
Supercat
Danke für die Antwort. Es hat ziemlich genau bestätigt, was ich dachte, also muss es richtig sein. Ich entschied mich, die Antwort von xmoyxr zu akzeptieren, weil er das Konzept des Einfrierens von Objekten ansprach, denen ich zuvor noch nicht begegnet war.
Cerad