13
13
*/
14
14
final class ResourceOutputStream implements OutputStream
15
15
{
16
+ /** @deprecated No longer used. */
16
17
const MAX_CONSECUTIVE_EMPTY_WRITES = 3 ;
18
+
17
19
const LARGE_CHUNK_SIZE = 128 * 1024 ;
18
20
19
21
/** @var resource|null */
@@ -58,8 +60,6 @@ public function __construct($stream, int $chunkSize = null)
58
60
$ resource = &$ this ->resource ;
59
61
60
62
$ this ->watcher = Loop::onWritable ($ stream , static function ($ watcher , $ stream ) use ($ writes , &$ chunkSize , &$ writable , &$ resource ) {
61
- static $ emptyWrites = 0 ;
62
-
63
63
try {
64
64
while (!$ writes ->isEmpty ()) {
65
65
/** @var Deferred $deferred */
@@ -75,6 +75,11 @@ public function __construct($stream, int $chunkSize = null)
75
75
throw new ClosedException ("The stream was closed by the peer " );
76
76
}
77
77
78
+ $ error = null ;
79
+ \set_error_handler (static function (int $ errno ) use (&$ error ) {
80
+ $ error = $ errno ;
81
+ });
82
+
78
83
// Error reporting suppressed since fwrite() emits E_WARNING if the pipe is broken or the buffer is full.
79
84
// Use conditional, because PHP doesn't like getting null passed
80
85
if ($ chunkSize ) {
@@ -83,6 +88,8 @@ public function __construct($stream, int $chunkSize = null)
83
88
$ written = @\fwrite ($ stream , $ data );
84
89
}
85
90
91
+ \restore_error_handler ();
92
+
86
93
\assert (
87
94
$ written !== false || \PHP_VERSION_ID >= 70400 , // PHP 7.4+ returns false on EPIPE.
88
95
"Trying to write on a previously fclose()'d resource. Do NOT manually fclose() resources the still referenced in the loop. "
@@ -98,21 +105,14 @@ public function __construct($stream, int $chunkSize = null)
98
105
}
99
106
100
107
// Broken pipes between processes on macOS/FreeBSD do not detect EOF properly.
101
- if ($ written === 0 || $ written === false ) {
102
- if ($ emptyWrites ++ > self ::MAX_CONSECUTIVE_EMPTY_WRITES ) {
103
- $ message = "Failed to write to stream after multiple attempts " ;
104
- if ($ error = \error_get_last ()) {
105
- $ message .= \sprintf ("; %s " , $ error ["message " ]);
106
- }
107
- throw new StreamException ($ message );
108
+ if (($ written === 0 || $ written === false ) && $ error !== null ) {
109
+ $ message = "Failed to write to stream " ;
110
+ if ($ error = \error_get_last ()) {
111
+ $ message .= \sprintf ("; %s " , $ error ["message " ]);
108
112
}
109
-
110
- $ writes ->unshift ([$ data , $ previous , $ deferred ]);
111
- return ;
113
+ throw new StreamException ($ message );
112
114
}
113
115
114
- $ emptyWrites = 0 ;
115
-
116
116
if ($ length > $ written ) {
117
117
$ data = \substr ($ data , $ written );
118
118
$ writes ->unshift ([$ data , $ written + $ previous , $ deferred ]);
0 commit comments