diff --git a/src/Buffer.php b/src/Buffer.php index 9c6d60f..cce322d 100644 --- a/src/Buffer.php +++ b/src/Buffer.php @@ -14,13 +14,15 @@ class Buffer extends EventEmitter implements WritableStreamInterface private $writable = true; private $loop; private $data = ''; - private $lastError; public function __construct($stream, LoopInterface $loop) { + if (!is_resource($stream) || get_resource_type($stream) !== "stream") { + throw new \InvalidArgumentException('First parameter must be a valid stream resource'); + } + $this->stream = $stream; $this->loop = $loop; - $this->lastErrorFlush(); } public function isWritable() @@ -73,15 +75,15 @@ public function close() public function handleWrite() { - if (!is_resource($this->stream)) { - $this->emit('error', array(new \RuntimeException('Tried to write to invalid stream.'), $this)); - - return; - } - - $this->lastErrorFlush(); - - set_error_handler(array($this, 'errorHandler')); + $error = null; + set_error_handler(function ($errno, $errstr, $errfile, $errline) use (&$error) { + $error = array( + 'message' => $errstr, + 'number' => $errno, + 'file' => $errfile, + 'line' => $errline + ); + }); $sent = fwrite($this->stream, $this->data); @@ -94,23 +96,21 @@ public function handleWrite() // to keep the stream open for further tries to write. // Should this turn out to be a permanent error later, it will eventually // send *nothing* and we can detect this. - if ($sent === 0 && $this->lastError['number'] > 0) { - $this->emit('error', array( - new \ErrorException( - $this->lastError['message'], + if ($sent === 0 || $sent === false) { + if ($error === null) { + $error = new \RuntimeException('Send failed'); + } else { + $error = new \ErrorException( + $error['message'], 0, - $this->lastError['number'], - $this->lastError['file'], - $this->lastError['line'] - ), - $this - )); + $error['number'], + $error['file'], + $error['line'] + ); + } - return; - } + $this->emit('error', array(new \RuntimeException('Unable to write to stream: ' . $error->getMessage(), 0, $error), $this)); - if ($sent === 0) { - $this->emit('error', array(new \RuntimeException('Send failed'), $this)); return; } @@ -128,21 +128,4 @@ public function handleWrite() $this->emit('full-drain', array($this)); } } - - private function errorHandler($errno, $errstr, $errfile, $errline) - { - $this->lastError['number'] = $errno; - $this->lastError['message'] = $errstr; - $this->lastError['file'] = $errfile; - $this->lastError['line'] = $errline; - } - - private function lastErrorFlush() { - $this->lastError = array( - 'number' => 0, - 'message' => '', - 'file' => '', - 'line' => 0, - ); - } } diff --git a/tests/BufferTest.php b/tests/BufferTest.php index e235211..f3eae3a 100644 --- a/tests/BufferTest.php +++ b/tests/BufferTest.php @@ -18,6 +18,18 @@ public function testConstructor() $buffer->on('error', $this->expectCallableNever()); } + /** + * @covers React\Stream\Buffer::__construct + * @expectedException InvalidArgumentException + */ + public function testConstructorThrowsIfNotAValidStreamResource() + { + $stream = null; + $loop = $this->createLoopMock(); + + new Buffer($stream, $loop); + } + /** * @covers React\Stream\Buffer::write * @covers React\Stream\Buffer::handleWrite @@ -249,11 +261,10 @@ public function testWritingToClosedBufferShouldNotWriteToStream() /** * @covers React\Stream\Buffer::handleWrite - * @covers React\Stream\Buffer::errorHandler */ - public function testError() + public function testErrorWhenStreamResourceIsInvalid() { - $stream = null; + $stream = fopen('php://temp', 'r+'); $loop = $this->createWriteableLoopMock(); $error = null; @@ -263,9 +274,16 @@ public function testError() $error = $message; }); + // invalidate stream resource + fclose($stream); + $buffer->write('Attempting to write to bad stream'); + $this->assertInstanceOf('Exception', $error); - $this->assertSame('Tried to write to invalid stream.', $error->getMessage()); + + // the error messages differ between PHP versions, let's just check substrings + $this->assertContains('Unable to write to stream: ', $error->getMessage()); + $this->assertContains(' not a valid stream resource', $error->getMessage(), '', true); } public function testWritingToClosedStream() @@ -290,7 +308,7 @@ public function testWritingToClosedStream() $buffer->write('bar'); $this->assertInstanceOf('Exception', $error); - $this->assertSame('fwrite(): send of 3 bytes failed with errno=32 Broken pipe', $error->getMessage()); + $this->assertSame('Unable to write to stream: fwrite(): send of 3 bytes failed with errno=32 Broken pipe', $error->getMessage()); } private function createWriteableLoopMock()