20
20
/**
21
21
* Class JsonStream.
22
22
*
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 .
26
26
*
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 .
29
29
*
30
30
* @package FastForward\Http\Message
31
31
*/
32
32
final class JsonStream extends Stream implements JsonStreamInterface
33
33
{
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
+ */
34
42
public const ENCODING_OPTIONS = JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ;
35
43
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
+
36
54
/**
37
55
* Constructs a new JsonStream instance with the provided payload.
38
56
*
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().
41
59
*
42
60
* @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 .
44
62
*/
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
+
49
68
parent ::__construct (fopen ('php://temp ' , 'wb+ ' ));
50
69
51
70
$ this ->write ($ this ->jsonEncode ($ this ->payload , $ this ->encodingOptions ));
52
71
$ this ->rewind ();
53
72
}
54
73
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
+ */
55
81
public function getPayload (): mixed
56
82
{
57
83
return $ this ->payload ;
58
84
}
59
85
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
+ */
60
96
public function withPayload (mixed $ payload ): self
61
97
{
62
98
return new self ($ payload );
@@ -65,11 +101,11 @@ public function withPayload(mixed $payload): self
65
101
/**
66
102
* Encodes the given data as JSON, enforcing proper error handling.
67
103
*
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 .
70
106
*
71
107
* @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.
73
109
*
74
110
* @return string the JSON-encoded string representation of the data
75
111
*
@@ -79,10 +115,10 @@ public function withPayload(mixed $payload): self
79
115
private function jsonEncode (mixed $ data , int $ encodingOptions ): string
80
116
{
81
117
if (\is_resource ($ data )) {
82
- throw new \InvalidArgumentException ('Cannot JSON encode resources ' );
118
+ throw new \InvalidArgumentException ('Cannot JSON encode resources. ' );
83
119
}
84
120
85
- // Clear json_last_error()
121
+ // Reset potential previous errors
86
122
json_encode (null );
87
123
88
124
return json_encode ($ data , $ encodingOptions | JSON_THROW_ON_ERROR );
0 commit comments