2020/**
2121 * Class JsonStream.
2222 *
23- * Extends Nyholm's PSR-7 Stream implementation to provide JSON-specific stream functionality .
24- * This class SHALL encapsulate a JSON-encoded payload within a PHP stream, while retaining the original
25- * payload in a decoded form for convenient access .
23+ * Provides a JSON-specific stream implementation, extending Nyholm's PSR-7 Stream .
24+ * This class SHALL encapsulate a JSON-encoded payload within an in-memory PHP stream,
25+ * while retaining the original decoded payload for convenient retrieval .
2626 *
27- * Implementations MUST properly handle JSON encoding errors and enforce the prohibition of resource types
28- * within JSON payloads .
27+ * Implementations of this class MUST properly handle JSON encoding errors and SHALL explicitly
28+ * prohibit the inclusion of resource types within the JSON payload .
2929 *
3030 * @package FastForward\Http\Message
3131 */
3232final class JsonStream extends Stream implements JsonStreamInterface
3333{
34+ /**
35+ * JSON encoding flags to be applied by default.
36+ *
37+ * The options JSON_THROW_ON_ERROR, JSON_UNESCAPED_SLASHES, and JSON_UNESCAPED_UNICODE
38+ * SHALL be applied to enforce strict error handling and produce readable JSON output.
39+ *
40+ * @var int
41+ */
3442 public const ENCODING_OPTIONS = JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ;
3543
44+ /**
45+ * @var mixed The decoded payload provided to the stream. This MUST be JSON-encodable and MUST NOT contain resources.
46+ */
47+ private mixed $ payload = [];
48+
49+ /**
50+ * @var int The JSON encoding options to be applied. Defaults to self::ENCODING_OPTIONS.
51+ */
52+ private int $ encodingOptions = self ::ENCODING_OPTIONS ;
53+
3654 /**
3755 * Constructs a new JsonStream instance with the provided payload.
3856 *
39- * The payload SHALL be JSON-encoded and written to an in-memory PHP stream. The original payload is retained
40- * in decoded form for later retrieval via {@see getPayload()} .
57+ * The payload SHALL be JSON-encoded and written to an in-memory stream. The original payload is retained
58+ * in its decoded form for later access via getPayload().
4159 *
4260 * @param mixed $payload The data to encode as JSON. MUST be JSON-encodable. Resources are explicitly prohibited.
43- * @param int $encodingOptions Optional JSON encoding flags as defined by {@see json_encode()}. Defaults to 0 .
61+ * @param int $encodingOptions Optional JSON encoding flags. If omitted, ENCODING_OPTIONS will be applied .
4462 */
45- public function __construct (
46- private mixed $ payload = [],
47- private int $ encodingOptions = self ::ENCODING_OPTIONS
48- ) {
63+ public function __construct (mixed $ payload = [], int $ encodingOptions = self ::ENCODING_OPTIONS )
64+ {
65+ $ this ->payload = $ payload ;
66+ $ this ->encodingOptions = $ encodingOptions ;
67+
4968 parent ::__construct (fopen ('php://temp ' , 'wb+ ' ));
5069
5170 $ this ->write ($ this ->jsonEncode ($ this ->payload , $ this ->encodingOptions ));
5271 $ this ->rewind ();
5372 }
5473
74+ /**
75+ * Retrieves the decoded payload associated with the stream.
76+ *
77+ * This method SHALL return the original JSON-encodable payload provided during construction or via withPayload().
78+ *
79+ * @return mixed the decoded payload
80+ */
5581 public function getPayload (): mixed
5682 {
5783 return $ this ->payload ;
5884 }
5985
86+ /**
87+ * Returns a new instance of the stream with the specified payload.
88+ *
89+ * This method MUST return a new JsonStream instance with the body replaced by a stream
90+ * containing the JSON-encoded form of the new payload. The current instance SHALL remain unchanged.
91+ *
92+ * @param mixed $payload the new JSON-encodable payload
93+ *
94+ * @return self a new JsonStream instance containing the updated payload
95+ */
6096 public function withPayload (mixed $ payload ): self
6197 {
6298 return new self ($ payload );
@@ -65,11 +101,11 @@ public function withPayload(mixed $payload): self
65101 /**
66102 * Encodes the given data as JSON, enforcing proper error handling.
67103 *
68- * If the provided data is a resource, this method SHALL throw an {@see \InvalidArgumentException} as resources
69- * cannot be represented in JSON format .
104+ * If the provided data is a resource, this method SHALL throw an \InvalidArgumentException,
105+ * as resource types are not supported by JSON .
70106 *
71107 * @param mixed $data the data to encode as JSON
72- * @param int $encodingOptions JSON encoding options, combined with JSON_THROW_ON_ERROR
108+ * @param int $encodingOptions JSON encoding options to apply. JSON_THROW_ON_ERROR will always be enforced.
73109 *
74110 * @return string the JSON-encoded string representation of the data
75111 *
@@ -79,10 +115,10 @@ public function withPayload(mixed $payload): self
79115 private function jsonEncode (mixed $ data , int $ encodingOptions ): string
80116 {
81117 if (\is_resource ($ data )) {
82- throw new \InvalidArgumentException ('Cannot JSON encode resources ' );
118+ throw new \InvalidArgumentException ('Cannot JSON encode resources. ' );
83119 }
84120
85- // Clear json_last_error()
121+ // Reset potential previous errors
86122 json_encode (null );
87123
88124 return json_encode ($ data , $ encodingOptions | JSON_THROW_ON_ERROR );
0 commit comments