diff --git a/src/Connection/ConnectionLimitingPool.php b/src/Connection/ConnectionLimitingPool.php index 68adc65c..b51fd749 100644 --- a/src/Connection/ConnectionLimitingPool.php +++ b/src/Connection/ConnectionLimitingPool.php @@ -42,8 +42,6 @@ private static function formatUri(Request $request): string return $scheme . '://' . $authority; } - private int $connectionLimit; - private ConnectionFactory $connectionFactory; /** @var array>> */ @@ -67,14 +65,13 @@ private static function formatUri(Request $request): string private int $openConnectionCount = 0; - private function __construct(int $connectionLimit, ?ConnectionFactory $connectionFactory = null) + private function __construct(private readonly int $connectionLimit, ?ConnectionFactory $connectionFactory = null) { if ($connectionLimit < 1) { throw new \Error('The connection limit must be greater than 0'); } - $this->connectionLimit = $connectionLimit; - $this->connectionFactory = $connectionFactory ?? new DefaultConnectionFactory; + $this->connectionFactory = $connectionFactory ?? new DefaultConnectionFactory(); } public function __clone() diff --git a/src/Connection/DefaultConnectionFactory.php b/src/Connection/DefaultConnectionFactory.php index 0b342786..7ba029c7 100644 --- a/src/Connection/DefaultConnectionFactory.php +++ b/src/Connection/DefaultConnectionFactory.php @@ -18,14 +18,13 @@ final class DefaultConnectionFactory implements ConnectionFactory { - private ?Socket\SocketConnector $connector; + private readonly ConnectContext $connectContext; - private ?ConnectContext $connectContext; - - public function __construct(?Socket\SocketConnector $connector = null, ?ConnectContext $connectContext = null) - { - $this->connector = $connector; - $this->connectContext = $connectContext; + public function __construct( + private readonly ?Socket\SocketConnector $connector = null, + ?ConnectContext $connectContext = null, + ) { + $this->connectContext = $connectContext ?? new ConnectContext(); } public function create(Request $request, Cancellation $cancellation): Connection @@ -33,7 +32,7 @@ public function create(Request $request, Cancellation $cancellation): Connection $connectStart = now(); $connector = $this->connector ?? Socket\socketConnector(); - $connectContext = $this->connectContext ?? new ConnectContext; + $connectContext = $this->connectContext; $uri = $request->getUri(); $scheme = $uri->getScheme(); diff --git a/src/Connection/Http1Connection.php b/src/Connection/Http1Connection.php index e798d4df..44440ffe 100644 --- a/src/Connection/Http1Connection.php +++ b/src/Connection/Http1Connection.php @@ -69,8 +69,6 @@ final class Http1Connection implements Connection /** @var list<\Closure():void>|null */ private ?array $onClose = []; - private float $timeoutGracePeriod; - private float $lastUsedAt; private bool $explicitTimeout = false; @@ -87,13 +85,12 @@ public function __construct( Socket $socket, private readonly float $connectDuration, private readonly ?float $tlsHandshakeDuration, - float $timeoutGracePeriod = 2 + private readonly float $timeoutGracePeriod = 2, ) { $this->socket = $socket; $this->localAddress = $socket->getLocalAddress(); $this->remoteAddress = $socket->getRemoteAddress(); $this->tlsInfo = $socket->getTlsInfo(); - $this->timeoutGracePeriod = $timeoutGracePeriod; $this->lastUsedAt = now(); $this->watchIdleConnection(); } diff --git a/src/Connection/HttpStream.php b/src/Connection/HttpStream.php index 387596f9..4371e550 100644 --- a/src/Connection/HttpStream.php +++ b/src/Connection/HttpStream.php @@ -12,66 +12,73 @@ use Amp\Socket\TlsInfo; use function Amp\Http\Client\processRequest; +/** + * @psalm-type RequestCallbackType = callable(Request, Cancellation, HttpStream):Response + * @psalm-type ReleaseCallbackType = callable():void + */ final class HttpStream implements Stream { use ForbidSerialization; use ForbidCloning; + /** + * @param RequestCallbackType $RequestCallbackType + * @param ReleaseCallbackType $ReleaseCallbackType + */ public static function fromConnection( Connection $connection, - callable $requestCallback, - callable $releaseCallback + callable $RequestCallbackType, + callable $ReleaseCallbackType ): self { return new self( $connection->getLocalAddress(), $connection->getRemoteAddress(), $connection->getTlsInfo(), - $requestCallback, - $releaseCallback + $RequestCallbackType, + $ReleaseCallbackType, ); } - public static function fromStream(Stream $stream, callable $requestCallback, callable $releaseCallback): self + /** + * @param RequestCallbackType $RequestCallbackType + * @param ReleaseCallbackType $ReleaseCallbackType + */ + public static function fromStream(Stream $stream, callable $RequestCallbackType, callable $ReleaseCallbackType): self { return new self( $stream->getLocalAddress(), $stream->getRemoteAddress(), $stream->getTlsInfo(), - $requestCallback, - $releaseCallback + $RequestCallbackType, + $ReleaseCallbackType, ); } - private SocketAddress $localAddress; - - private SocketAddress $remoteAddress; - - private ?TlsInfo $tlsInfo; - /** @var callable */ - private $requestCallback; + private $RequestCallbackType; /** @var callable|null */ - private $releaseCallback; + private $ReleaseCallbackType; + /** + * @param RequestCallbackType $RequestCallbackType + * @param ReleaseCallbackType $ReleaseCallbackType + */ private function __construct( - SocketAddress $localAddress, - SocketAddress $remoteAddress, - ?TlsInfo $tlsInfo, - callable $requestCallback, - callable $releaseCallback + private readonly SocketAddress $localAddress, + private readonly SocketAddress $remoteAddress, + private readonly ?TlsInfo $tlsInfo, + callable $RequestCallbackType, + callable $ReleaseCallbackType, ) { - $this->localAddress = $localAddress; - $this->remoteAddress = $remoteAddress; - $this->tlsInfo = $tlsInfo; - $this->requestCallback = $requestCallback; - $this->releaseCallback = $releaseCallback; + $this->RequestCallbackType = $RequestCallbackType; + $this->ReleaseCallbackType = $ReleaseCallbackType; } public function __destruct() { - if ($this->releaseCallback !== null) { - ($this->releaseCallback)(); + if ($this->ReleaseCallbackType !== null) { + ($this->ReleaseCallbackType)(); } } @@ -80,13 +87,13 @@ public function __destruct() */ public function request(Request $request, Cancellation $cancellation): Response { - if ($this->releaseCallback === null) { + if ($this->ReleaseCallbackType === null) { throw new \Error('A stream may only be used for a single request'); } - $this->releaseCallback = null; + $this->ReleaseCallbackType = null; - return processRequest($request, [], fn (): Response => ($this->requestCallback)($request, $cancellation, $this)); + return processRequest($request, [], fn (): Response => ($this->RequestCallbackType)($request, $cancellation, $this)); } public function getLocalAddress(): SocketAddress diff --git a/src/Connection/InterceptedStream.php b/src/Connection/InterceptedStream.php index cee6f045..1b40cfdf 100644 --- a/src/Connection/InterceptedStream.php +++ b/src/Connection/InterceptedStream.php @@ -21,13 +21,10 @@ final class InterceptedStream implements Stream private static \WeakMap $requestInterceptors; - private Stream $stream; - private ?NetworkInterceptor $interceptor; - public function __construct(Stream $stream, NetworkInterceptor $interceptor) + public function __construct(private readonly Stream $stream, NetworkInterceptor $interceptor) { - $this->stream = $stream; $this->interceptor = $interceptor; } @@ -37,14 +34,14 @@ public function __construct(Stream $stream, NetworkInterceptor $interceptor) public function request(Request $request, Cancellation $cancellation): Response { return processRequest($request, [], function () use ($request, $cancellation): Response { - if (!$this->interceptor) { + $interceptor = $this->interceptor; + $this->interceptor = null; + + if (!$interceptor) { throw new \Error(__METHOD__ . ' may only be invoked once per instance. ' . 'If you need to implement retries or otherwise issue multiple requests, register an ApplicationInterceptor to do so.'); } - $interceptor = $this->interceptor; - $this->interceptor = null; - /** @psalm-suppress RedundantPropertyInitializationCheck */ self::$requestInterceptors ??= new \WeakMap(); $requestInterceptors = self::$requestInterceptors[$request] ?? []; diff --git a/src/Connection/Internal/Http1Parser.php b/src/Connection/Internal/Http1Parser.php index cee0482a..7b8914b3 100644 --- a/src/Connection/Internal/Http1Parser.php +++ b/src/Connection/Internal/Http1Parser.php @@ -10,12 +10,17 @@ use Amp\Http\Client\Request; use Amp\Http\Client\Response; use Amp\Http\Http1\Rfc7230; +use Amp\Http\HttpMessage; use Amp\Http\HttpStatus; use Amp\Http\InvalidHeaderException; use function Amp\Http\Client\events; use function Amp\Http\mapHeaderPairs; -/** @internal */ +/** + * @internal + * + * @psalm-import-type HeaderMapType from HttpMessage + */ final class Http1Parser { use ForbidSerialization; @@ -34,10 +39,6 @@ final class Http1Parser public const TRAILERS_START = 4; public const TRAILERS = 5; - private Request $request; - - private Stream $stream; - private ?Response $response = null; private int $state = self::AWAITING_HEADERS; @@ -57,26 +58,20 @@ final class Http1Parser private bool $complete = false; - private int $maxHeaderBytes; - - private int $maxBodyBytes; + private readonly int $maxHeaderBytes; - /** @var callable */ - private $bodyDataCallback; - - /** @var callable */ - private $trailersCallback; + private readonly int $maxBodyBytes; + /** + * @param \Closure(string):void $bodyDataCallback + * @param \Closure(HeaderMapType):void $trailersCallback + */ public function __construct( - Request $request, - Stream $stream, - callable $bodyDataCallback, - callable $trailersCallback, + private readonly Request $request, + private readonly Stream $stream, + private readonly \Closure $bodyDataCallback, + private readonly \Closure $trailersCallback, ) { - $this->request = $request; - $this->stream = $stream; - $this->bodyDataCallback = $bodyDataCallback; - $this->trailersCallback = $trailersCallback; $this->maxHeaderBytes = $request->getHeaderSizeLimit(); $this->maxBodyBytes = $request->getBodySizeLimit(); } diff --git a/src/HttpClient.php b/src/HttpClient.php index beba5096..93d7b18c 100644 --- a/src/HttpClient.php +++ b/src/HttpClient.php @@ -11,15 +11,13 @@ */ final class HttpClient implements DelegateHttpClient { - private DelegateHttpClient $httpClient; - - /** @var EventListener[] */ - private array $eventListeners; - - public function __construct(DelegateHttpClient $httpClient, array $eventListeners) - { - $this->httpClient = $httpClient; - $this->eventListeners = $eventListeners; + /** + * @param EventListener[] $eventListeners + */ + public function __construct( + private readonly DelegateHttpClient $httpClient, + private readonly array $eventListeners, + ) { } /** @@ -32,7 +30,7 @@ public function request(Request $request, ?Cancellation $cancellation = null): R return processRequest( $request, $this->eventListeners, - fn () => $this->httpClient->request($request, $cancellation ?? new NullCancellation()) + fn () => $this->httpClient->request($request, $cancellation ?? new NullCancellation()), ); } } diff --git a/src/InterceptedHttpClient.php b/src/InterceptedHttpClient.php index 49bb2b3f..9aa2683b 100644 --- a/src/InterceptedHttpClient.php +++ b/src/InterceptedHttpClient.php @@ -13,21 +13,14 @@ final class InterceptedHttpClient implements DelegateHttpClient private static \WeakMap $requestInterceptors; - private DelegateHttpClient $httpClient; - - private ApplicationInterceptor $interceptor; - - /** @var EventListener[] */ - private array $eventListeners; - + /** + * @param EventListener[] $eventListeners + */ public function __construct( - DelegateHttpClient $httpClient, - ApplicationInterceptor $interceptor, - array $eventListeners + private readonly DelegateHttpClient $httpClient, + private readonly ApplicationInterceptor $interceptor, + private readonly array $eventListeners, ) { - $this->httpClient = $httpClient; - $this->interceptor = $interceptor; - $this->eventListeners = $eventListeners; } public function request(Request $request, Cancellation $cancellation): Response @@ -35,6 +28,7 @@ public function request(Request $request, Cancellation $cancellation): Response return processRequest($request, $this->eventListeners, function () use ($request, $cancellation) { /** @psalm-suppress RedundantPropertyInitializationCheck */ self::$requestInterceptors ??= new \WeakMap(); + $requestInterceptors = self::$requestInterceptors[$request] ?? []; $requestInterceptors[] = $this->interceptor; self::$requestInterceptors[$request] = $requestInterceptors; diff --git a/src/Interceptor/DecompressResponse.php b/src/Interceptor/DecompressResponse.php index 0177f37c..acdddb47 100644 --- a/src/Interceptor/DecompressResponse.php +++ b/src/Interceptor/DecompressResponse.php @@ -17,7 +17,7 @@ final class DecompressResponse implements NetworkInterceptor use ForbidCloning; use ForbidSerialization; - private bool $hasZlib; + private readonly bool $hasZlib; public function __construct() { diff --git a/src/Interceptor/FollowRedirects.php b/src/Interceptor/FollowRedirects.php index e40edc65..5b05aa4a 100644 --- a/src/Interceptor/FollowRedirects.php +++ b/src/Interceptor/FollowRedirects.php @@ -105,9 +105,9 @@ private static function mergePaths(string $basePath, string $pathToMerge): strin return self::removeDotSegments(\implode('/', $parts)); } - private int $maxRedirects; + private readonly int $maxRedirects; - private bool $autoReferrer; + private readonly bool $autoReferrer; public function __construct(int $limit, bool $autoReferrer = true) { diff --git a/src/Interceptor/MatchOrigin.php b/src/Interceptor/MatchOrigin.php index 71f2def3..129558e1 100644 --- a/src/Interceptor/MatchOrigin.php +++ b/src/Interceptor/MatchOrigin.php @@ -19,27 +19,26 @@ final class MatchOrigin implements ApplicationInterceptor use ForbidSerialization; /** @var ApplicationInterceptor[] */ - private array $originMap = []; - - private ?ApplicationInterceptor $default; + private readonly array $originMap; /** * @param ApplicationInterceptor[] $originMap * * @throws HttpException */ - public function __construct(array $originMap, ?ApplicationInterceptor $default = null) + public function __construct(array $originMap, private readonly ?ApplicationInterceptor $default = null) { + $validatedMap = []; foreach ($originMap as $origin => $interceptor) { if (!$interceptor instanceof ApplicationInterceptor) { $type = \get_debug_type($interceptor); throw new HttpException('Origin map must be a map from origin to ApplicationInterceptor, got ' . $type); } - $this->originMap[$this->checkOrigin($origin)] = $interceptor; + $validatedMap[$this->checkOrigin($origin)] = $interceptor; } - $this->default = $default; + $this->originMap = $validatedMap; } public function request( diff --git a/src/Interceptor/ModifyRequest.php b/src/Interceptor/ModifyRequest.php index 241cbe18..63438fe9 100644 --- a/src/Interceptor/ModifyRequest.php +++ b/src/Interceptor/ModifyRequest.php @@ -17,15 +17,11 @@ class ModifyRequest implements NetworkInterceptor, ApplicationInterceptor use ForbidCloning; use ForbidSerialization; - /** @var \Closure(Request):(Request|null) */ - private \Closure $mapper; - /** * @param \Closure(Request):(Request|null) $mapper */ - public function __construct(\Closure $mapper) + public function __construct(private readonly \Closure $mapper) { - $this->mapper = $mapper; } final public function requestViaNetwork( diff --git a/src/Interceptor/ModifyResponse.php b/src/Interceptor/ModifyResponse.php index a3f4eb4f..01b3d449 100644 --- a/src/Interceptor/ModifyResponse.php +++ b/src/Interceptor/ModifyResponse.php @@ -17,15 +17,11 @@ class ModifyResponse implements NetworkInterceptor, ApplicationInterceptor use ForbidCloning; use ForbidSerialization; - /** @var \Closure(Response):Response */ - private \Closure $mapper; - /** * @param \Closure(Response):Response $mapper */ - public function __construct(\Closure $mapper) + public function __construct(private readonly \Closure $mapper) { - $this->mapper = $mapper; } final public function requestViaNetwork( diff --git a/src/Interceptor/RetryRequests.php b/src/Interceptor/RetryRequests.php index 03030450..6a616dc1 100644 --- a/src/Interceptor/RetryRequests.php +++ b/src/Interceptor/RetryRequests.php @@ -16,11 +16,8 @@ final class RetryRequests implements ApplicationInterceptor use ForbidCloning; use ForbidSerialization; - private int $retryLimit; - - public function __construct(int $retryLimit) + public function __construct(private readonly int $retryLimit) { - $this->retryLimit = $retryLimit; } public function request(