diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 54c6135..82359bf 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] steps: - name: Checkout code @@ -31,12 +31,37 @@ jobs: - name: Execute tests run: composer test + psr-7_2: + name: PHP PSR-7 2.0 + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.2 + tools: composer + coverage: none + + - name: Install dependencies + run: | + rm src/MessageFactory/SlimMessageFactory.php src/StreamFactory/SlimStreamFactory.php src/UriFactory/SlimUriFactory.php spec/MessageFactory/SlimMessageFactorySpec.php spec/StreamFactory/SlimStreamFactorySpec.php spec/UriFactory/SlimUriFactorySpec.php + composer remove --dev "slim/slim" --no-interaction --no-update + composer require "psr/http-message:^2.0" --no-interaction --no-update + composer update --prefer-dist --prefer-stable --no-interaction --no-progress + + - name: Execute tests + run: composer test + lowest: name: PHP ${{ matrix.php }} Lowest runs-on: ubuntu-latest strategy: matrix: - php: ['7.1', '7.2', '7.3', '7.4'] + php: ['7.2', '7.3', '7.4'] steps: - name: Checkout code diff --git a/CHANGELOG.md b/CHANGELOG.md index b31e885..9016f8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## [1.14.0] - 2023-04-14 +## [1.15.0] - 2023-05-10 + +- Actually make compatible with PSR-7 1.1 and 2.0 +- Drop support for PHP 7.1 + +## [1.14.0] - 2023-04-14 (broken) + +**This release is not actually compatible with PSR-7 1.1 or 2.0** - Allow installation with http-message (PSR-7) version 2 in addition to version 1. - Support for PHP 8.2 diff --git a/composer.json b/composer.json index 0ecaad9..05bd274 100644 --- a/composer.json +++ b/composer.json @@ -15,10 +15,10 @@ } ], "require": { - "php": "^7.1 || ^8.0", + "php": "^7.2 || ^8.0", "clue/stream-filter": "^1.5", "php-http/message-factory": "^1.0.2", - "psr/http-message": "^1.0 || ^2.0" + "psr/http-message": "^1.1 || ^2.0" }, "provide": { "php-http/message-factory-implementation": "1.0" @@ -26,10 +26,10 @@ "require-dev": { "ext-zlib": "*", "ergebnis/composer-normalize": "^2.6", - "guzzlehttp/psr7": "^1.0", + "guzzlehttp/psr7": "^1.0 || ^2.0", "phpspec/phpspec": "^5.1 || ^6.3 || ^7.1", "slim/slim": "^3.0", - "laminas/laminas-diactoros": "^2.0" + "laminas/laminas-diactoros": "^2.0 || ^3.0" }, "suggest": { "ext-zlib": "Used with compressor/decompressor streams", diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 226065a..a5cda2b 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -115,26 +115,6 @@ parameters: count: 1 path: src/CookieUtil.php - - - message: "#^Method Http\\\\Message\\\\Encoding\\\\ChunkStream\\:\\:fill\\(\\) has no return type specified\\.$#" - count: 1 - path: src/Encoding/ChunkStream.php - - - - message: "#^Method Http\\\\Message\\\\Encoding\\\\FilteredStream\\:\\:fill\\(\\) has no return type specified\\.$#" - count: 1 - path: src/Encoding/FilteredStream.php - - - - message: "#^Method Http\\\\Message\\\\Encoding\\\\FilteredStream\\:\\:rewind\\(\\) has no return type specified\\.$#" - count: 1 - path: src/Encoding/FilteredStream.php - - - - message: "#^Method Http\\\\Message\\\\Encoding\\\\FilteredStream\\:\\:seek\\(\\) has no return type specified\\.$#" - count: 1 - path: src/Encoding/FilteredStream.php - - message: "#^Method Http\\\\Message\\\\MessageFactory\\\\DiactorosMessageFactory\\:\\:createRequest\\(\\) has parameter \\$headers with no value type specified in iterable type array\\.$#" count: 1 @@ -180,26 +160,11 @@ parameters: count: 1 path: src/RequestMatcher/RequestMatcher.php - - - message: "#^Property Http\\\\Message\\\\Stream\\\\BufferedStream\\:\\:\\$size \\(int\\) does not accept int\\|null\\.$#" - count: 1 - path: src/Stream/BufferedStream.php - - message: "#^Property Http\\\\Message\\\\Stream\\\\BufferedStream\\:\\:\\$resource \\(resource\\) does not accept resource\\|false\\.$#" count: 2 path: src/Stream/BufferedStream.php - - - message: "#^Dead catch \\- Exception is already caught#" - count: 1 - path: src/Stream/BufferedStream.php - - - - message: "#^Method Http\\\\Message\\\\Stream\\\\BufferedStream\\:\\:detach\\(\\) should return resource\\|null but empty return statement found\\.$#" - count: 1 - path: src/Stream/BufferedStream.php - - message: "#^Property Http\\\\Message\\\\Stream\\\\BufferedStream\\:\\:\\$stream \\(Psr\\\\Http\\\\Message\\\\StreamInterface\\) does not accept null\\.$#" count: 1 @@ -210,36 +175,6 @@ parameters: count: 1 path: src/Stream/BufferedStream.php - - - message: "#^Method Http\\\\Message\\\\Stream\\\\BufferedStream\\:\\:getSize\\(\\) should return int\\|null but empty return statement found\\.$#" - count: 1 - path: src/Stream/BufferedStream.php - - - - message: "#^Method Http\\\\Message\\\\Stream\\\\BufferedStream\\:\\:tell\\(\\) should return int but returns int\\|false\\.$#" - count: 1 - path: src/Stream/BufferedStream.php - - - - message: "#^Method Http\\\\Message\\\\Stream\\\\BufferedStream\\:\\:seek\\(\\) has no return type specified\\.$#" - count: 1 - path: src/Stream/BufferedStream.php - - - - message: "#^Method Http\\\\Message\\\\Stream\\\\BufferedStream\\:\\:rewind\\(\\) has no return type specified\\.$#" - count: 1 - path: src/Stream/BufferedStream.php - - - - message: "#^Parameter \\#1 \\$string of function strlen expects string, string\\|false given\\.$#" - count: 1 - path: src/Stream/BufferedStream.php - - - - message: "#^Method Http\\\\Message\\\\Stream\\\\BufferedStream\\:\\:read\\(\\) should return string but returns string\\|false\\.$#" - count: 1 - path: src/Stream/BufferedStream.php - - message: "#^Parameter \\#1 \\$stream of class Slim\\\\Http\\\\Stream constructor expects resource, resource\\|false given\\.$#" count: 1 diff --git a/spec/Decorator/MessageDecoratorSpec.php b/spec/Decorator/MessageDecoratorSpec.php index 5c28dcd..8c8bd33 100644 --- a/spec/Decorator/MessageDecoratorSpec.php +++ b/spec/Decorator/MessageDecoratorSpec.php @@ -69,9 +69,9 @@ public function it_can_check_a_header(MessageInterface $message) public function it_has_a_header(MessageInterface $message) { - $message->getHeader('Content-Type')->willReturn('application/xml'); + $message->getHeader('Content-Type')->willReturn(['application/xml']); - $this->getHeader('Content-Type')->shouldReturn('application/xml'); + $this->getHeader('Content-Type')->shouldReturn(['application/xml']); } public function it_has_a_header_line(MessageInterface $message) diff --git a/spec/Decorator/StreamDecoratorSpec.php b/spec/Decorator/StreamDecoratorSpec.php index 46bb0d5..1315579 100644 --- a/spec/Decorator/StreamDecoratorSpec.php +++ b/spec/Decorator/StreamDecoratorSpec.php @@ -95,7 +95,7 @@ public function it_checks_whether_the_stream_is_writable(StreamInterface $stream public function it_writes_to_the_stream(StreamInterface $stream) { - $stream->write('body')->shouldBeCalled(); + $stream->write('body')->shouldBeCalled()->willReturn(4); $this->write('body'); } diff --git a/spec/Encoding/FilteredStreamStubSpec.php b/spec/Encoding/FilteredStreamStubSpec.php index dc4db8f..fbaf68c 100644 --- a/spec/Encoding/FilteredStreamStubSpec.php +++ b/spec/Encoding/FilteredStreamStubSpec.php @@ -57,12 +57,12 @@ public function it_does_not_know_the_content_size() class FilteredStreamStub extends FilteredStream { - protected function readFilter() + protected function readFilter(): string { return 'convert.base64-encode'; } - protected function writeFilter() + protected function writeFilter(): string { return 'convert.base64-encode'; } diff --git a/spec/Encoding/MemoryStream.php b/spec/Encoding/MemoryStream.php index 72acab7..a751b43 100644 --- a/spec/Encoding/MemoryStream.php +++ b/spec/Encoding/MemoryStream.php @@ -28,12 +28,12 @@ public function __construct($body = '', $chunkSize = 8192) $this->chunkSize = $chunkSize; } - public function __toString() + public function __toString(): string { return $this->getContents(); } - public function close() + public function close(): void { fclose($this->resource); } @@ -46,64 +46,64 @@ public function detach() return $resource; } - public function getSize() + public function getSize(): int { return $this->size; } - public function tell() + public function tell(): int { return ftell($this->resource); } - public function eof() + public function eof(): bool { return feof($this->resource); } - public function isSeekable() + public function isSeekable(): bool { return true; } - public function seek($offset, $whence = SEEK_SET) + public function seek(int $offset, int $whence = SEEK_SET): void { fseek($this->resource, $offset, $whence); } - public function rewind() + public function rewind(): void { $this->seek(0); } - public function isWritable() + public function isWritable(): bool { return true; } - public function write($string) + public function write(string $string): int { - fwrite($this->resource, $string); + return fwrite($this->resource, $string); } - public function isReadable() + public function isReadable(): bool { return true; } - public function read($length) + public function read(int $length): string { return fread($this->resource, min($this->chunkSize, $length)); } - public function getContents() + public function getContents(): string { $this->rewind(); return $this->read($this->size); } - public function getMetadata($key = null) + public function getMetadata(string $key = null) { $metadata = stream_get_meta_data($this->resource); diff --git a/spec/Formatter/CurlCommandFormatterSpec.php b/spec/Formatter/CurlCommandFormatterSpec.php index 36524da..e6ed104 100644 --- a/spec/Formatter/CurlCommandFormatterSpec.php +++ b/spec/Formatter/CurlCommandFormatterSpec.php @@ -25,7 +25,8 @@ public function it_formats_the_request(RequestInterface $request, UriInterface $ $request->getUri()->willReturn($uri); $request->getBody()->willReturn($body); - $uri->withFragment('')->shouldBeCalled()->willReturn('http://foo.com/bar'); + $uri->withFragment('')->shouldBeCalled()->willReturn($uri); + $uri->__toString()->shouldBeCalled()->willReturn('http://foo.com/bar'); $request->getMethod()->willReturn('GET'); $request->getProtocolVersion()->willReturn('1.1'); @@ -43,9 +44,10 @@ public function it_formats_post_request(RequestInterface $request, UriInterface $body->__toString()->willReturn('body " data'." test' bar"); $body->getSize()->willReturn(1); $body->isSeekable()->willReturn(true); - $body->rewind()->willReturn(true); + $body->rewind()->shouldBeCalled(); - $uri->withFragment('')->shouldBeCalled()->willReturn('http://foo.com/bar'); + $uri->withFragment('')->shouldBeCalled()->willReturn($uri); + $uri->__toString()->shouldBeCalled()->willReturn('http://foo.com/bar'); $request->getMethod()->willReturn('POST'); $request->getProtocolVersion()->willReturn('2.0'); @@ -65,10 +67,10 @@ public function it_formats_the_request_with_user_agent(RequestInterface $request $request->getUri()->willReturn($uri); $request->getBody()->willReturn($body); - $uri->withFragment('')->shouldBeCalled()->willReturn('http://foo.com/bar'); + $uri->withFragment('')->shouldBeCalled()->willReturn($uri); + $uri->__toString()->shouldBeCalled()->willReturn('http://foo.com/bar'); $request->getMethod()->willReturn('GET'); $request->getProtocolVersion()->willReturn('1.1'); - $uri->withFragment('')->shouldBeCalled()->willReturn('http://foo.com/bar'); $request->getHeaders()->willReturn(['user-agent' => ['foobar-browser']]); $this->formatRequest($request)->shouldReturn("curl 'http://foo.com/bar' -A 'foobar-browser'"); @@ -82,9 +84,10 @@ public function it_formats_requests_with_null_bytes(RequestInterface $request, U $body->__toString()->willReturn("\0"); $body->getSize()->willReturn(1); $body->isSeekable()->willReturn(true); - $body->rewind()->willReturn(true); + $body->rewind()->shouldBeCalled(); - $uri->withFragment('')->willReturn('http://foo.com/bar'); + $uri->withFragment('')->shouldBeCalled()->willReturn($uri); + $uri->__toString()->shouldBeCalled()->willReturn('http://foo.com/bar'); $request->getMethod()->willReturn('POST'); $request->getProtocolVersion()->willReturn('1.1'); $request->getHeaders()->willReturn([]); @@ -100,9 +103,10 @@ public function it_formats_requests_with_line_break(RequestInterface $request, U $body->__toString()->willReturn("foo\nbar"); $body->getSize()->willReturn(1); $body->isSeekable()->willReturn(true); - $body->rewind()->willReturn(true); + $body->rewind()->shouldBeCalled(); - $uri->withFragment('')->willReturn('http://foo.com/bar'); + $uri->withFragment('')->shouldBeCalled()->willReturn($uri); + $uri->__toString()->shouldBeCalled()->willReturn('http://foo.com/bar'); $request->getMethod()->willReturn('POST'); $request->getProtocolVersion()->willReturn('1.1'); $request->getHeaders()->willReturn([]); @@ -120,7 +124,8 @@ public function it_formats_requests_with_nonseekable_body(RequestInterface $requ $body->__toString()->shouldNotBeCalled(); $body->rewind()->shouldNotBeCalled(); - $uri->withFragment('')->willReturn('http://foo.com/bar'); + $uri->withFragment('')->shouldBeCalled()->willReturn($uri); + $uri->__toString()->shouldBeCalled()->willReturn('http://foo.com/bar'); $request->getMethod()->willReturn('POST'); $request->getProtocolVersion()->willReturn('1.1'); $request->getHeaders()->willReturn([]); @@ -133,12 +138,13 @@ public function it_formats_requests_with_long_body(RequestInterface $request, Ur $request->getUri()->willReturn($uri); $request->getBody()->willReturn($body); - $body->__toString()->willReturn('a very long body'); + $body->__toString()->shouldNotBeCalled(); $body->getSize()->willReturn(2097153); $body->isSeekable()->willReturn(true); - $body->rewind()->willReturn(true); + $body->rewind()->shouldNotBeCalled(); - $uri->withFragment('')->willReturn('http://foo.com/bar'); + $uri->withFragment('')->shouldBeCalled()->willReturn($uri); + $uri->__toString()->shouldBeCalled()->willReturn('http://foo.com/bar'); $request->getMethod()->willReturn('POST'); $request->getProtocolVersion()->willReturn('1.1'); $request->getHeaders()->willReturn([]); diff --git a/src/Decorator/MessageDecorator.php b/src/Decorator/MessageDecorator.php index 0ffc7ca..4ec4690 100644 --- a/src/Decorator/MessageDecorator.php +++ b/src/Decorator/MessageDecorator.php @@ -20,26 +20,18 @@ trait MessageDecorator * * Since the underlying Message is immutable as well * exposing it is not an issue, because it's state cannot be altered - * - * @return MessageInterface */ - public function getMessage() + public function getMessage(): MessageInterface { return $this->message; } - /** - * {@inheritdoc} - */ - public function getProtocolVersion() + public function getProtocolVersion(): string { return $this->message->getProtocolVersion(); } - /** - * {@inheritdoc} - */ - public function withProtocolVersion($version) + public function withProtocolVersion(string $version): MessageInterface { $new = clone $this; $new->message = $this->message->withProtocolVersion($version); @@ -47,42 +39,27 @@ public function withProtocolVersion($version) return $new; } - /** - * {@inheritdoc} - */ - public function getHeaders() + public function getHeaders(): array { return $this->message->getHeaders(); } - /** - * {@inheritdoc} - */ - public function hasHeader($header) + public function hasHeader(string $header): bool { return $this->message->hasHeader($header); } - /** - * {@inheritdoc} - */ - public function getHeader($header) + public function getHeader(string $header): array { return $this->message->getHeader($header); } - /** - * {@inheritdoc} - */ - public function getHeaderLine($header) + public function getHeaderLine(string $header): string { return $this->message->getHeaderLine($header); } - /** - * {@inheritdoc} - */ - public function withHeader($header, $value) + public function withHeader(string $header, $value): MessageInterface { $new = clone $this; $new->message = $this->message->withHeader($header, $value); @@ -90,10 +67,7 @@ public function withHeader($header, $value) return $new; } - /** - * {@inheritdoc} - */ - public function withAddedHeader($header, $value) + public function withAddedHeader(string $header, $value): MessageInterface { $new = clone $this; $new->message = $this->message->withAddedHeader($header, $value); @@ -101,10 +75,7 @@ public function withAddedHeader($header, $value) return $new; } - /** - * {@inheritdoc} - */ - public function withoutHeader($header) + public function withoutHeader(string $header): MessageInterface { $new = clone $this; $new->message = $this->message->withoutHeader($header); @@ -112,18 +83,12 @@ public function withoutHeader($header) return $new; } - /** - * {@inheritdoc} - */ - public function getBody() + public function getBody(): StreamInterface { return $this->message->getBody(); } - /** - * {@inheritdoc} - */ - public function withBody(StreamInterface $body) + public function withBody(StreamInterface $body): MessageInterface { $new = clone $this; $new->message = $this->message->withBody($body); diff --git a/src/Decorator/RequestDecorator.php b/src/Decorator/RequestDecorator.php index bd254a8..1392a76 100644 --- a/src/Decorator/RequestDecorator.php +++ b/src/Decorator/RequestDecorator.php @@ -16,10 +16,8 @@ trait RequestDecorator /** * Exchanges the underlying request with another. - * - * @return self */ - public function withRequest(RequestInterface $request) + public function withRequest(RequestInterface $request): RequestInterface { $new = clone $this; $new->message = $request; @@ -27,18 +25,12 @@ public function withRequest(RequestInterface $request) return $new; } - /** - * {@inheritdoc} - */ - public function getRequestTarget() + public function getRequestTarget(): string { return $this->message->getRequestTarget(); } - /** - * {@inheritdoc} - */ - public function withRequestTarget($requestTarget) + public function withRequestTarget(string $requestTarget): RequestInterface { $new = clone $this; $new->message = $this->message->withRequestTarget($requestTarget); @@ -46,18 +38,12 @@ public function withRequestTarget($requestTarget) return $new; } - /** - * {@inheritdoc} - */ - public function getMethod() + public function getMethod(): string { return $this->message->getMethod(); } - /** - * {@inheritdoc} - */ - public function withMethod($method) + public function withMethod(string $method): RequestInterface { $new = clone $this; $new->message = $this->message->withMethod($method); @@ -65,18 +51,12 @@ public function withMethod($method) return $new; } - /** - * {@inheritdoc} - */ - public function getUri() + public function getUri(): UriInterface { return $this->message->getUri(); } - /** - * {@inheritdoc} - */ - public function withUri(UriInterface $uri, $preserveHost = false) + public function withUri(UriInterface $uri, bool $preserveHost = false): RequestInterface { $new = clone $this; $new->message = $this->message->withUri($uri, $preserveHost); diff --git a/src/Decorator/ResponseDecorator.php b/src/Decorator/ResponseDecorator.php index 20319ed..0b75438 100644 --- a/src/Decorator/ResponseDecorator.php +++ b/src/Decorator/ResponseDecorator.php @@ -15,10 +15,8 @@ trait ResponseDecorator /** * Exchanges the underlying response with another. - * - * @return self */ - public function withResponse(ResponseInterface $response) + public function withResponse(ResponseInterface $response): ResponseInterface { $new = clone $this; $new->message = $response; @@ -26,18 +24,12 @@ public function withResponse(ResponseInterface $response) return $new; } - /** - * {@inheritdoc} - */ - public function getStatusCode() + public function getStatusCode(): int { return $this->message->getStatusCode(); } - /** - * {@inheritdoc} - */ - public function withStatus($code, $reasonPhrase = '') + public function withStatus(int $code, string $reasonPhrase = ''): ResponseInterface { $new = clone $this; $new->message = $this->message->withStatus($code, $reasonPhrase); @@ -45,10 +37,7 @@ public function withStatus($code, $reasonPhrase = '') return $new; } - /** - * {@inheritdoc} - */ - public function getReasonPhrase() + public function getReasonPhrase(): string { return $this->message->getReasonPhrase(); } diff --git a/src/Decorator/StreamDecorator.php b/src/Decorator/StreamDecorator.php index f405c7a..b1f306d 100644 --- a/src/Decorator/StreamDecorator.php +++ b/src/Decorator/StreamDecorator.php @@ -16,122 +16,77 @@ trait StreamDecorator */ protected $stream; - /** - * {@inheritdoc} - */ - public function __toString() + public function __toString(): string { return $this->stream->__toString(); } - /** - * {@inheritdoc} - */ - public function close() + public function close(): void { $this->stream->close(); } - /** - * {@inheritdoc} - */ public function detach() { return $this->stream->detach(); } - /** - * {@inheritdoc} - */ - public function getSize() + public function getSize(): ?int { return $this->stream->getSize(); } - /** - * {@inheritdoc} - */ - public function tell() + public function tell(): int { return $this->stream->tell(); } - /** - * {@inheritdoc} - */ - public function eof() + public function eof(): bool { return $this->stream->eof(); } - /** - * {@inheritdoc} - */ - public function isSeekable() + public function isSeekable(): bool { return $this->stream->isSeekable(); } - /** - * {@inheritdoc} - */ - public function seek($offset, $whence = SEEK_SET) + public function seek(int $offset, int $whence = SEEK_SET): void { $this->stream->seek($offset, $whence); } - /** - * {@inheritdoc} - */ - public function rewind() + public function rewind(): void { $this->stream->rewind(); } - /** - * {@inheritdoc} - */ - public function isWritable() + public function isWritable(): bool { return $this->stream->isWritable(); } - /** - * {@inheritdoc} - */ - public function write($string) + public function write(string $string): int { return $this->stream->write($string); } - /** - * {@inheritdoc} - */ - public function isReadable() + public function isReadable(): bool { return $this->stream->isReadable(); } - /** - * {@inheritdoc} - */ - public function read($length) + public function read(int $length): string { return $this->stream->read($length); } - /** - * {@inheritdoc} - */ - public function getContents() + public function getContents(): string { return $this->stream->getContents(); } - /** - * {@inheritdoc} - */ - public function getMetadata($key = null) + public function getMetadata(string $key = null) { return $this->stream->getMetadata($key); } diff --git a/src/Encoding/ChunkStream.php b/src/Encoding/ChunkStream.php index 74c2fbd..362ed78 100644 --- a/src/Encoding/ChunkStream.php +++ b/src/Encoding/ChunkStream.php @@ -9,26 +9,17 @@ */ class ChunkStream extends FilteredStream { - /** - * {@inheritdoc} - */ - protected function readFilter() + protected function readFilter(): string { return 'chunk'; } - /** - * {@inheritdoc} - */ - protected function writeFilter() + protected function writeFilter(): string { return 'dechunk'; } - /** - * {@inheritdoc} - */ - protected function fill() + protected function fill(): void { parent::fill(); diff --git a/src/Encoding/CompressStream.php b/src/Encoding/CompressStream.php index bdb740a..7e89388 100644 --- a/src/Encoding/CompressStream.php +++ b/src/Encoding/CompressStream.php @@ -27,18 +27,12 @@ public function __construct(StreamInterface $stream, $level = -1) $this->writeFilterCallback = Filter\fun($this->writeFilter(), ['window' => 15]); } - /** - * {@inheritdoc} - */ - protected function readFilter() + protected function readFilter(): string { return 'zlib.deflate'; } - /** - * {@inheritdoc} - */ - protected function writeFilter() + protected function writeFilter(): string { return 'zlib.inflate'; } diff --git a/src/Encoding/DechunkStream.php b/src/Encoding/DechunkStream.php index 4cade83..c1fe3a6 100644 --- a/src/Encoding/DechunkStream.php +++ b/src/Encoding/DechunkStream.php @@ -11,18 +11,12 @@ */ class DechunkStream extends FilteredStream { - /** - * {@inheritdoc} - */ - protected function readFilter() + protected function readFilter(): string { return 'dechunk'; } - /** - * {@inheritdoc} - */ - protected function writeFilter() + protected function writeFilter(): string { return 'chunk'; } diff --git a/src/Encoding/DecompressStream.php b/src/Encoding/DecompressStream.php index ab3a345..aa3fdf0 100644 --- a/src/Encoding/DecompressStream.php +++ b/src/Encoding/DecompressStream.php @@ -27,18 +27,12 @@ public function __construct(StreamInterface $stream, $level = -1) $this->writeFilterCallback = Filter\fun($this->writeFilter(), ['window' => 15, 'level' => $level]); } - /** - * {@inheritdoc} - */ - protected function readFilter() + protected function readFilter(): string { return 'zlib.inflate'; } - /** - * {@inheritdoc} - */ - protected function writeFilter() + protected function writeFilter(): string { return 'zlib.deflate'; } diff --git a/src/Encoding/DeflateStream.php b/src/Encoding/DeflateStream.php index 2ab3e00..d18dd0a 100644 --- a/src/Encoding/DeflateStream.php +++ b/src/Encoding/DeflateStream.php @@ -26,7 +26,7 @@ public function __construct(StreamInterface $stream, $level = -1) /** * {@inheritdoc} */ - protected function readFilter() + protected function readFilter(): string { return 'zlib.deflate'; } @@ -34,7 +34,7 @@ protected function readFilter() /** * {@inheritdoc} */ - protected function writeFilter() + protected function writeFilter(): string { return 'zlib.inflate'; } diff --git a/src/Encoding/Filter/Chunk.php b/src/Encoding/Filter/Chunk.php index 538e270..7a9e18f 100644 --- a/src/Encoding/Filter/Chunk.php +++ b/src/Encoding/Filter/Chunk.php @@ -9,11 +9,7 @@ */ class Chunk extends \php_user_filter { - /** - * {@inheritdoc} - */ - #[\ReturnTypeWillChange] - public function filter($in, $out, &$consumed, $closing) + public function filter($in, $out, &$consumed, $closing): int { while ($bucket = stream_bucket_make_writeable($in)) { $lenbucket = stream_bucket_new($this->stream, dechex($bucket->datalen)."\r\n"); diff --git a/src/Encoding/FilteredStream.php b/src/Encoding/FilteredStream.php index a6aec25..d2e0e45 100644 --- a/src/Encoding/FilteredStream.php +++ b/src/Encoding/FilteredStream.php @@ -75,10 +75,7 @@ public function __construct(StreamInterface $stream, $readFilterOptions = null, $this->stream = $stream; } - /** - * {@inheritdoc} - */ - public function read($length) + public function read(int $length): string { if (strlen($this->buffer) >= $length) { $read = substr($this->buffer, 0, $length); @@ -101,10 +98,7 @@ public function read($length) return $read.$this->read($length - strlen($read)); } - /** - * {@inheritdoc} - */ - public function eof() + public function eof(): bool { return $this->stream->eof() && '' === $this->buffer; } @@ -116,7 +110,7 @@ public function eof() * This allow to get last data in the PHP buffer otherwise this * bug is present : https://bugs.php.net/bug.php?id=48725 */ - protected function fill() + protected function fill(): void { $readFilterCallback = $this->readFilterCallback; $this->buffer .= $readFilterCallback($this->stream->read(self::BUFFER_SIZE)); @@ -129,7 +123,7 @@ protected function fill() /** * {@inheritdoc} */ - public function getContents() + public function getContents(): string { $buffer = ''; @@ -149,15 +143,12 @@ public function getContents() /** * Always returns null because we can't tell the size of a stream when we filter. */ - public function getSize() + public function getSize(): ?int { return null; } - /** - * {@inheritdoc} - */ - public function __toString() + public function __toString(): string { return $this->getContents(); } @@ -167,24 +158,24 @@ public function __toString() * * We would need to buffer and process everything to allow seeking. */ - public function isSeekable() + public function isSeekable(): bool { return false; } /** - * {@inheritdoc} + * Filtered streams are not seekable and can thus not be rewound. */ - public function rewind() + public function rewind(): void { @trigger_error('Filtered streams are not seekable. This method will start raising an exception in the next major version', E_USER_DEPRECATED); $this->doRewind(); } /** - * {@inheritdoc} + * Filtered streams are not seekable. */ - public function seek($offset, $whence = SEEK_SET) + public function seek(int $offset, int $whence = SEEK_SET): void { @trigger_error('Filtered streams are not seekable. This method will start raising an exception in the next major version', E_USER_DEPRECATED); $this->doSeek($offset, $whence); @@ -193,11 +184,9 @@ public function seek($offset, $whence = SEEK_SET) /** * Returns the read filter name. * - * @return string - * * @deprecated since version 1.5, will be removed in 2.0 */ - public function getReadFilter() + public function getReadFilter(): string { @trigger_error('The '.__CLASS__.'::'.__METHOD__.' method is deprecated since version 1.5 and will be removed in 2.0.', E_USER_DEPRECATED); @@ -206,19 +195,15 @@ public function getReadFilter() /** * Returns the write filter name. - * - * @return string */ - abstract protected function readFilter(); + abstract protected function readFilter(): string; /** * Returns the write filter name. * - * @return string - * * @deprecated since version 1.5, will be removed in 2.0 */ - public function getWriteFilter() + public function getWriteFilter(): string { @trigger_error('The '.__CLASS__.'::'.__METHOD__.' method is deprecated since version 1.5 and will be removed in 2.0.', E_USER_DEPRECATED); @@ -227,8 +212,6 @@ public function getWriteFilter() /** * Returns the write filter name. - * - * @return string */ - abstract protected function writeFilter(); + abstract protected function writeFilter(): string; } diff --git a/src/Encoding/GzipDecodeStream.php b/src/Encoding/GzipDecodeStream.php index 92b5dad..9872499 100644 --- a/src/Encoding/GzipDecodeStream.php +++ b/src/Encoding/GzipDecodeStream.php @@ -30,7 +30,7 @@ public function __construct(StreamInterface $stream, $level = -1) /** * {@inheritdoc} */ - protected function readFilter() + protected function readFilter(): string { return 'zlib.inflate'; } @@ -38,7 +38,7 @@ protected function readFilter() /** * {@inheritdoc} */ - protected function writeFilter() + protected function writeFilter(): string { return 'zlib.deflate'; } diff --git a/src/Encoding/GzipEncodeStream.php b/src/Encoding/GzipEncodeStream.php index 13f097a..36018c2 100644 --- a/src/Encoding/GzipEncodeStream.php +++ b/src/Encoding/GzipEncodeStream.php @@ -30,7 +30,7 @@ public function __construct(StreamInterface $stream, $level = -1) /** * {@inheritdoc} */ - protected function readFilter() + protected function readFilter(): string { return 'zlib.deflate'; } @@ -38,7 +38,7 @@ protected function readFilter() /** * {@inheritdoc} */ - protected function writeFilter() + protected function writeFilter(): string { return 'zlib.inflate'; } diff --git a/src/Encoding/InflateStream.php b/src/Encoding/InflateStream.php index 06c5187..1abe88e 100644 --- a/src/Encoding/InflateStream.php +++ b/src/Encoding/InflateStream.php @@ -27,18 +27,12 @@ public function __construct(StreamInterface $stream, $level = -1) $this->writeFilterCallback = Filter\fun($this->writeFilter(), ['window' => -15, 'level' => $level]); } - /** - * {@inheritdoc} - */ - protected function readFilter() + protected function readFilter(): string { return 'zlib.inflate'; } - /** - * {@inheritdoc} - */ - protected function writeFilter() + protected function writeFilter(): string { return 'zlib.deflate'; } diff --git a/src/Stream/BufferedStream.php b/src/Stream/BufferedStream.php index 3d38731..cf23fc7 100644 --- a/src/Stream/BufferedStream.php +++ b/src/Stream/BufferedStream.php @@ -17,7 +17,7 @@ class BufferedStream implements StreamInterface /** @var resource The buffered resource used to seek previous data */ private $resource; - /** @var int size of the stream if available */ + /** @var int|null size of the stream if available */ private $size; /** @var StreamInterface The underlying stream decorated by this class */ @@ -49,10 +49,7 @@ public function __construct(StreamInterface $stream, $useFileBuffer = true, $mem } } - /** - * {@inheritdoc} - */ - public function __toString() + public function __toString(): string { try { $this->rewind(); @@ -60,15 +57,10 @@ public function __toString() return $this->getContents(); } catch (\Throwable $throwable) { return ''; - } catch (\Exception $exception) { // Layer to be BC with PHP 5, remove this when we only support PHP 7+ - return ''; } } - /** - * {@inheritdoc} - */ - public function close() + public function close(): void { if (null === $this->resource) { throw new \RuntimeException('Cannot close on a detached stream'); @@ -78,13 +70,10 @@ public function close() fclose($this->resource); } - /** - * {@inheritdoc} - */ public function detach() { if (null === $this->resource) { - return; + return null; } // Force reading the remaining data of the stream @@ -98,13 +87,10 @@ public function detach() return $resource; } - /** - * {@inheritdoc} - */ - public function getSize() + public function getSize(): ?int { if (null === $this->resource) { - return; + return null; } if (null === $this->size && $this->stream->eof()) { @@ -114,22 +100,21 @@ public function getSize() return $this->size; } - /** - * {@inheritdoc} - */ - public function tell() + public function tell(): int { if (null === $this->resource) { throw new \RuntimeException('Cannot tell on a detached stream'); } - return ftell($this->resource); + $tell = ftell($this->resource); + if (false === $tell) { + throw new \RuntimeException('ftell failed'); + } + + return $tell; } - /** - * {@inheritdoc} - */ - public function eof() + public function eof(): bool { if (null === $this->resource) { throw new \RuntimeException('Cannot call eof on a detached stream'); @@ -139,18 +124,12 @@ public function eof() return $this->stream->eof() && (ftell($this->resource) === $this->written); } - /** - * {@inheritdoc} - */ - public function isSeekable() + public function isSeekable(): bool { return null !== $this->resource; } - /** - * {@inheritdoc} - */ - public function seek($offset, $whence = SEEK_SET) + public function seek(int $offset, int $whence = SEEK_SET): void { if (null === $this->resource) { throw new \RuntimeException('Cannot seek on a detached stream'); @@ -159,10 +138,7 @@ public function seek($offset, $whence = SEEK_SET) fseek($this->resource, $offset, $whence); } - /** - * {@inheritdoc} - */ - public function rewind() + public function rewind(): void { if (null === $this->resource) { throw new \RuntimeException('Cannot rewind on a detached stream'); @@ -171,34 +147,22 @@ public function rewind() rewind($this->resource); } - /** - * {@inheritdoc} - */ - public function isWritable() + public function isWritable(): bool { return false; } - /** - * {@inheritdoc} - */ - public function write($string) + public function write(string $string): int { throw new \RuntimeException('Cannot write on this stream'); } - /** - * {@inheritdoc} - */ - public function isReadable() + public function isReadable(): bool { return null !== $this->resource; } - /** - * {@inheritdoc} - */ - public function read($length) + public function read(int $length): string { if (null === $this->resource) { throw new \RuntimeException('Cannot read on a detached stream'); @@ -213,6 +177,9 @@ public function read($length) if (ftell($this->resource) !== $this->written) { $read = fread($this->resource, $length); } + if (false === $read) { + throw new \RuntimeException('Failed to read from resource'); + } $bytesRead = strlen($read); @@ -227,10 +194,7 @@ public function read($length) return $read; } - /** - * {@inheritdoc} - */ - public function getContents() + public function getContents(): string { if (null === $this->resource) { throw new \RuntimeException('Cannot read on a detached stream'); @@ -245,17 +209,14 @@ public function getContents() return $read; } - /** - * {@inheritdoc} - */ - public function getMetadata($key = null) + public function getMetadata(?string $key = null) { if (null === $this->resource) { if (null === $key) { return []; } - return; + return null; } $metadata = stream_get_meta_data($this->resource); @@ -265,7 +226,7 @@ public function getMetadata($key = null) } if (!array_key_exists($key, $metadata)) { - return; + return null; } return $metadata[$key]; diff --git a/src/StreamFactory/GuzzleStreamFactory.php b/src/StreamFactory/GuzzleStreamFactory.php index 14d83e9..7a61a7c 100644 --- a/src/StreamFactory/GuzzleStreamFactory.php +++ b/src/StreamFactory/GuzzleStreamFactory.php @@ -23,6 +23,7 @@ public function createStream($body = null) return Utils::streamFor($body); } + // legacy support for guzzle/psr7 1.* return \GuzzleHttp\Psr7\stream_for($body); } }