CachingHttpClient
in package
implements
HttpClientInterface, ResetInterface
uses
AsyncDecoratorTrait, HttpClientTrait
Adds caching on top of an HTTP client (per RFC 9111).
Known omissions / partially supported features per RFC 9111:
- Range requests:
- All range requests ("partial content") are passed through and never cached.
- stale-while-revalidate:
- There's no actual "background revalidation" for stale responses, they will always be revalidated.
- min-fresh, max-stale, only-if-cached:
- Request directives are not parsed; the client ignores them.
Tags
Table of Contents
Interfaces
- HttpClientInterface
- Provides flexible methods for requesting HTTP resources synchronously or asynchronously.
- ResetInterface
- Provides a way to reset an object to its initial state.
Constants
- CACHEABLE_METHODS = ['GET', 'HEAD']
- The HTTP methods that are always cacheable.
- CACHEABLE_STATUS_CODES = [200, 203, 204, 300, 301, 404, 410]
- The status codes that are always cacheable.
- CONDITIONALLY_CACHEABLE_STATUS_CODES = [302, 303, 307, 308]
- The status codes that are cacheable if the response carries explicit cache directives.
- EXCLUDED_HEADERS = ['connection' => true, 'proxy-authenticate' => true, 'proxy-authentication-info' => true, 'proxy-authorization' => true]
- Headers that MUST NOT be stored as per RFC 9111 Section 3.1.
- MAX_HEURISTIC_FRESHNESS_TTL = 86400
- Maximum heuristic freshness lifetime in seconds (24 hours).
- RESPONSE_INFLUENCING_HEADERS = ['accept' => true, 'accept-charset' => true, 'accept-encoding' => true, 'accept-language' => true, 'authorization' => true, 'cookie' => true, 'expect' => true, 'host' => true, 'user-agent' => true]
- Headers that influence the response and may affect caching behavior.
- UNSAFE_METHODS = ['POST', 'PUT', 'DELETE', 'PATCH']
- The HTTP methods that will trigger a cache invalidation.
Properties
- $cache : TagAwareCacheInterface|HttpCache
- $CHUNK_SIZE : int
- $client : HttpClientInterface
- $defaultOptions : array<string|int, mixed>
- $maxTtl : int|null
- $sharedCache : bool
Methods
- __construct() : mixed
- request() : ResponseInterface
- Requests an HTTP resource.
- stream() : ResponseStreamInterface
- Yields responses chunk by chunk as they complete.
- withOptions() : static
- buildVariantKey() : string
- Build a variant key for caching, given an array of normalized headers and the vary fields.
- calculateExpiresAt() : int|null
- Calculates the expiration time of the response given the maximum age.
- createGatewayTimeoutResponse() : MockResponse
- createResponseFromCache() : MockResponse
- Creates a MockResponse object from cached data.
- dechunk() : string
- determineMaxAge() : int|null
- Determine the maximum age of the response.
- evaluateCacheFreshness() : Freshness
- Evaluates the freshness of a cached response based on its headers and expiration time.
- generateChunkKey() : string
- getCurrentAge() : int
- Retrieves the current age of the response from the headers.
- getMetadataKey() : string
- Generates a unique metadata key based on the request hash and varying headers.
- getProxy() : array<string|int, mixed>|null
- Loads proxy configuration from the same environment variables as curl when no proxy is explicitly set.
- getProxyUrl() : string|null
- hasExplicitExpiration() : bool
- Checks if the response has an explicit expiration.
- hash() : string
- isServerResponseCacheable() : bool
- Checks if the server response is cacheable according to the HTTP 1.1 specification (RFC 9111).
- jsonEncode() : string
- legacyRequest() : ResponseInterface
- mergeDefaultOptions() : array<string|int, mixed>
- mergeQueryString() : string|null
- Merges and encodes a query array with a query string.
- normalizeBody() : string|resource|Closure
- normalizeHeaders() : array<string|int, array<string|int, string>>
- normalizePeerFingerprint() : array<string|int, mixed>
- parseCacheControlHeader() : array<string, string|true>
- Parse the Cache-Control header and return an array of directive names as keys and their values as values, or true if the directive has no value.
- parseUrl() : array<string|int, mixed>
- Parses a URL and fixes its encoding if needed.
- prepareRequest() : array<string|int, mixed>
- Validates and normalizes method, URL and options, and merges them with defaults.
- removeDotSegments() : string
- Removes dot-segments from a path.
- resolveUrl() : array<string|int, mixed>
- Resolves a URL against a base URI.
- shouldBuffer() : bool
Constants
CACHEABLE_METHODS
The HTTP methods that are always cacheable.
private
mixed
CACHEABLE_METHODS
= ['GET', 'HEAD']
CACHEABLE_STATUS_CODES
The status codes that are always cacheable.
private
mixed
CACHEABLE_STATUS_CODES
= [200, 203, 204, 300, 301, 404, 410]
CONDITIONALLY_CACHEABLE_STATUS_CODES
The status codes that are cacheable if the response carries explicit cache directives.
private
mixed
CONDITIONALLY_CACHEABLE_STATUS_CODES
= [302, 303, 307, 308]
EXCLUDED_HEADERS
Headers that MUST NOT be stored as per RFC 9111 Section 3.1.
private
mixed
EXCLUDED_HEADERS
= ['connection' => true, 'proxy-authenticate' => true, 'proxy-authentication-info' => true, 'proxy-authorization' => true]
MAX_HEURISTIC_FRESHNESS_TTL
Maximum heuristic freshness lifetime in seconds (24 hours).
private
mixed
MAX_HEURISTIC_FRESHNESS_TTL
= 86400
RESPONSE_INFLUENCING_HEADERS
Headers that influence the response and may affect caching behavior.
private
mixed
RESPONSE_INFLUENCING_HEADERS
= ['accept' => true, 'accept-charset' => true, 'accept-encoding' => true, 'accept-language' => true, 'authorization' => true, 'cookie' => true, 'expect' => true, 'host' => true, 'user-agent' => true]
UNSAFE_METHODS
The HTTP methods that will trigger a cache invalidation.
private
mixed
UNSAFE_METHODS
= ['POST', 'PUT', 'DELETE', 'PATCH']
Properties
$cache
private
TagAwareCacheInterface|HttpCache
$cache
$CHUNK_SIZE
private
static int
$CHUNK_SIZE
= 16372
$client
private
HttpClientInterface
$client
$defaultOptions
private
array<string|int, mixed>
$defaultOptions
= self::OPTIONS_DEFAULTS
$maxTtl read-only
private
int|null
$maxTtl
= null
$sharedCache read-only
private
bool
$sharedCache
= true
Methods
__construct()
public
__construct(HttpClientInterface $client, TagAwareCacheInterface|StoreInterface $cache[, array<string|int, mixed> $defaultOptions = [] ][, bool $sharedCache = true ][, int|null $maxTtl = null ]) : mixed
Parameters
- $client : HttpClientInterface
- $cache : TagAwareCacheInterface|StoreInterface
- $defaultOptions : array<string|int, mixed> = []
- $sharedCache : bool = true
-
Indicates whether this cache is shared or private. When true, responses may be skipped from caching in presence of certain headers (e.g. Authorization) unless explicitly marked as public.
- $maxTtl : int|null = null
-
The maximum time-to-live (in seconds) for cached responses. If a server-provided TTL exceeds this value, it will be capped to this maximum.
request()
Requests an HTTP resource.
public
request(string $method, string $url[, array<string|int, mixed> $options = [] ]) : ResponseInterface
Responses MUST be lazy, but their status code MUST be checked even if none of their public methods are called.
Implementations are not required to support all options described above; they can also support more custom options; but in any case, they MUST throw a TransportExceptionInterface when an unsupported option is passed.
Parameters
- $method : string
- $url : string
- $options : array<string|int, mixed> = []
Return values
ResponseInterfacestream()
Yields responses chunk by chunk as they complete.
public
stream(ResponseInterface|iterable<string|int, mixed> $responses[, float|null $timeout = null ]) : ResponseStreamInterface
Parameters
- $responses : ResponseInterface|iterable<string|int, mixed>
-
One or more responses created by the current HTTP client
- $timeout : float|null = null
-
The idle timeout before yielding timeout chunks
Return values
ResponseStreamInterfacewithOptions()
public
withOptions(array<string|int, mixed> $options) : static
Parameters
- $options : array<string|int, mixed>
Return values
staticbuildVariantKey()
Build a variant key for caching, given an array of normalized headers and the vary fields.
private
static buildVariantKey(array<string, string|array<string|int, string>> $normalizedHeaders, array<string|int, string> $varyFields) : string
The key is an ampersand-separated string of "header=value" pairs, with the special case of "header=" for headers that are not present.
Parameters
- $normalizedHeaders : array<string, string|array<string|int, string>>
- $varyFields : array<string|int, string>
Return values
stringcalculateExpiresAt()
Calculates the expiration time of the response given the maximum age.
private
static calculateExpiresAt(int|null $maxAge) : int|null
Parameters
- $maxAge : int|null
-
The maximum age of the response in seconds, or null if it cannot be determined
Return values
int|null —The expiration time of the response as a Unix timestamp, or null if the maximum age is null
createGatewayTimeoutResponse()
private
static createGatewayTimeoutResponse(string $method, string $url, array<string|int, mixed> $options) : MockResponse
Parameters
- $method : string
- $url : string
- $options : array<string|int, mixed>
Return values
MockResponsecreateResponseFromCache()
Creates a MockResponse object from cached data.
private
createResponseFromCache(array{next_chunk: string, status_code: int, initial_age: int, headers: array, stored_at: int} $cachedData, string $method, string $url, array<string|int, mixed> $options, string $metadataKey) : MockResponse
This function constructs a MockResponse from the cached data, including the original request method, URL, and options, as well as the cached response headers and content. The constructed MockResponse is then returned.
Parameters
-
$cachedData
: array{next_chunk: string, status_code: int, initial_age: int, headers: array
, stored_at: int} - $method : string
- $url : string
- $options : array<string|int, mixed>
- $metadataKey : string
Return values
MockResponsedechunk()
private
static dechunk(string $body) : string
Parameters
- $body : string
Return values
stringdetermineMaxAge()
Determine the maximum age of the response.
private
determineMaxAge(array<string, string|array<string|int, string>> $headers, array<string, string|true> $cacheControl) : int|null
This method first checks for the presence of the s-maxage directive, and if present, returns its value minus the current age. If s-maxage is not present, it checks for the presence of the max-age directive, and if present, returns its value minus the current age. If neither directive is present, it checks the Expires header for a valid timestamp, and if present, returns the difference between the timestamp and the current time minus the current age.
If none of the above directives or headers are present, the method returns null.
Parameters
- $headers : array<string, string|array<string|int, string>>
-
An array of HTTP headers
- $cacheControl : array<string, string|true>
-
An array of parsed Cache-Control directives
Return values
int|null —The maximum age of the response, or null if it cannot be determined
evaluateCacheFreshness()
Evaluates the freshness of a cached response based on its headers and expiration time.
private
evaluateCacheFreshness(array{headers: array, expires_at: int|null} $data) : Freshness
This method determines the state of the cached response by analyzing the Cache-Control directives and the expiration timestamp.
Parameters
-
$data
: array{headers: array
, expires_at: int|null} -
The cached response data, including headers and expiration time
Return values
FreshnessgenerateChunkKey()
private
static generateChunkKey() : string
Return values
stringgetCurrentAge()
Retrieves the current age of the response from the headers.
private
static getCurrentAge(array<string, string|array<string|int, string>> $headers) : int
Parameters
- $headers : array<string, string|array<string|int, string>>
-
An array of HTTP headers
Return values
int —The age of the response in seconds, defaults to 0 if not present
getMetadataKey()
Generates a unique metadata key based on the request hash and varying headers.
private
static getMetadataKey(string $requestHash, array<string, string|array<string|int, string>> $normalizedHeaders, array<string|int, string> $varyFields) : string
Parameters
- $requestHash : string
-
A hash representing the request details
- $normalizedHeaders : array<string, string|array<string|int, string>>
-
Normalized headers of the request
- $varyFields : array<string|int, string>
-
Headers to consider for building the variant key
Return values
string —The metadata key composed of the request hash and variant key
getProxy()
Loads proxy configuration from the same environment variables as curl when no proxy is explicitly set.
private
static getProxy(string|null $proxy, array<string|int, mixed> $url, string|null $noProxy) : array<string|int, mixed>|null
Parameters
- $proxy : string|null
- $url : array<string|int, mixed>
- $noProxy : string|null
Return values
array<string|int, mixed>|nullgetProxyUrl()
private
static getProxyUrl(string|null $proxy, array<string|int, mixed> $url) : string|null
Parameters
- $proxy : string|null
- $url : array<string|int, mixed>
Return values
string|nullhasExplicitExpiration()
Checks if the response has an explicit expiration.
private
hasExplicitExpiration(array<string, string|array<string|int, string>> $headers, array<string, string|true> $cacheControl) : bool
This function will return true if the response has an explicit expiration time specified in the headers or in the Cache-Control directives, false otherwise.
Parameters
- $headers : array<string, string|array<string|int, string>>
- $cacheControl : array<string, string|true>
Return values
boolhash()
private
static hash(string $toHash) : string
Parameters
- $toHash : string
Return values
stringisServerResponseCacheable()
Checks if the server response is cacheable according to the HTTP 1.1 specification (RFC 9111).
private
isServerResponseCacheable(int $statusCode, array<string, string|array<string|int, string>> $requestHeaders, array<string, string|array<string|int, string>> $responseHeaders, array<string, string|true> $cacheControl) : bool
This function will return true if the server response can be cached, false otherwise.
Parameters
- $statusCode : int
- $requestHeaders : array<string, string|array<string|int, string>>
- $responseHeaders : array<string, string|array<string|int, string>>
- $cacheControl : array<string, string|true>
Return values
booljsonEncode()
private
static jsonEncode(mixed $value[, int|null $flags = null ][, int $maxDepth = 512 ]) : string
Parameters
- $value : mixed
- $flags : int|null = null
- $maxDepth : int = 512
Tags
Return values
stringlegacyRequest()
private
legacyRequest(string $method, string $url[, array<string|int, mixed> $options = [] ]) : ResponseInterface
Parameters
- $method : string
- $url : string
- $options : array<string|int, mixed> = []
Return values
ResponseInterfacemergeDefaultOptions()
private
static mergeDefaultOptions(array<string|int, mixed> $options, array<string|int, mixed> $defaultOptions[, bool $allowExtraOptions = false ]) : array<string|int, mixed>
Parameters
- $options : array<string|int, mixed>
- $defaultOptions : array<string|int, mixed>
- $allowExtraOptions : bool = false
Tags
Return values
array<string|int, mixed>mergeQueryString()
Merges and encodes a query array with a query string.
private
static mergeQueryString(string|null $queryString, array<string|int, mixed> $queryArray, bool $replace) : string|null
Parameters
- $queryString : string|null
- $queryArray : array<string|int, mixed>
- $replace : bool
Tags
Return values
string|nullnormalizeBody()
private
static normalizeBody(array<string|int, mixed>|string|resource|Traversable|Closure $body[, array<string|int, mixed> &$normalizedHeaders = [] ]) : string|resource|Closure
Parameters
- $body : array<string|int, mixed>|string|resource|Traversable|Closure
- $normalizedHeaders : array<string|int, mixed> = []
Tags
Return values
string|resource|ClosurenormalizeHeaders()
private
static normalizeHeaders(array<string|int, mixed> $headers) : array<string|int, array<string|int, string>>
Parameters
- $headers : array<string|int, mixed>
Tags
Return values
array<string|int, array<string|int, string>>normalizePeerFingerprint()
private
static normalizePeerFingerprint(mixed $fingerprint) : array<string|int, mixed>
Parameters
- $fingerprint : mixed
Tags
Return values
array<string|int, mixed>parseCacheControlHeader()
Parse the Cache-Control header and return an array of directive names as keys and their values as values, or true if the directive has no value.
private
static parseCacheControlHeader(array<string, string|array<string|int, string>> $header) : array<string, string|true>
Parameters
- $header : array<string, string|array<string|int, string>>
-
The Cache-Control header as an array of strings
Return values
array<string, string|true> —The parsed Cache-Control directives
parseUrl()
Parses a URL and fixes its encoding if needed.
private
static parseUrl(string $url[, array<string|int, mixed> $query = [] ][, array<string|int, mixed> $allowedSchemes = ['http' => 80, 'https' => 443] ]) : array<string|int, mixed>
Parameters
- $url : string
- $query : array<string|int, mixed> = []
- $allowedSchemes : array<string|int, mixed> = ['http' => 80, 'https' => 443]
Tags
Return values
array<string|int, mixed>prepareRequest()
Validates and normalizes method, URL and options, and merges them with defaults.
private
static prepareRequest(string|null $method, string|null $url, array<string|int, mixed> $options[, array<string|int, mixed> $defaultOptions = [] ][, bool $allowExtraOptions = false ]) : array<string|int, mixed>
Parameters
- $method : string|null
- $url : string|null
- $options : array<string|int, mixed>
- $defaultOptions : array<string|int, mixed> = []
- $allowExtraOptions : bool = false
Tags
Return values
array<string|int, mixed>removeDotSegments()
Removes dot-segments from a path.
private
static removeDotSegments(string $path) : string
Parameters
- $path : string
Tags
Return values
stringresolveUrl()
Resolves a URL against a base URI.
private
static resolveUrl(array<string|int, mixed> $url, array<string|int, mixed>|null $base[, array<string|int, mixed> $queryDefaults = [] ]) : array<string|int, mixed>
Parameters
- $url : array<string|int, mixed>
- $base : array<string|int, mixed>|null
- $queryDefaults : array<string|int, mixed> = []
Tags
Return values
array<string|int, mixed>shouldBuffer()
private
static shouldBuffer(array<string|int, mixed> $headers) : bool
Parameters
- $headers : array<string|int, mixed>