Search by

bitandblack / request-cache

TobiasKöngeterBit&Black

Caching of HTTP requested data with zero-latency reads: expired data is refreshed by background PHP processes, so your script never waits on the network. Works with any PSR-18/PSR-17 HTTP implementation via HTTP Discovery.

Package info

bitbucket.org/wirbelwild/request-cache

Homepage

pkg:composer/bitandblack/request-cache

Statistics

Installs: 1 713

Dependents: 0

Suggesters: 0

1.10.0 2026-09-22 07:39 UTC

This package is auto-updated.

Last update: 2026-09-22 07:39:28 UTC


README

PHP from Packagist Latest Stable Version Total Downloads License

Bit&Black Logo

Bit&Black Request Cache

Caching of HTTP requested data, done right: smooth, non-blocking and with zero-latency reads.

The response is never requested inside your script. Instead, this library hands the HTTP request to a separate background PHP process and returns immediately. Your code never wait for the network.

Key benefits

  • Zero-latency reads. A cache hit returns instantly. An expired entry still returns the last stored response while a fresh request upgrades it in the background (stale-while-revalidate). An unknown URL returns your default value immediately and fetches the data in the background, so the next call is already fast.
  • Never blocks your script. The actual HTTP request is executed by a detached PHP CLI process that keeps working after your PHP-FPM/Apache request has already finished and the response has been sent. This is impossible with single-process "async" HTTP clients, which keep your worker busy until the network has answered.
  • Pluggable HTTP layer. No hard dependency on a specific HTTP client. The library discovers an installed PSR-18 client and PSR-17 factories via php-http/discovery. Any implementation — Guzzle, Symfony HttpClient, and so on — works out of the box, both as the real client and as the PSR-7 factory.
  • Simple API. Each request carries its own time-to-live (TTL) that decides when a refresh is needed. RequestHandler implements Psr\Http\Client\ClientInterface, so it can be dropped in wherever a PSR-18 client is expected.

Why not just an async HTTP client?

Async HTTP clients like symfony/http-client or guzzlehttp/promises solve a different problem: concurrency within a single process. They multiplex many sockets on an event loop, but the current PHP process stays busy until those requests finish, and they know nothing about caching or expiry.

This library optimizes for a different scenario — serving cached data with zero latency, even when the underlying source is slow or unavailable:

  • Visitors always get an instant response; the slow network call happens off to the side.
  • Background processes survive the request lifecycle, so a long-running request never keeps your users waiting.
  • Caching and refresh are built in: one TTL value decides when to re-request, nothing else to configure.

If you need to fetch many URLs concurrently within a single script, an async HTTP client remains the right tool — and Request Cache can even use one as its underlying client via a custom request callback (see below).

Installation

This library is available for the use with Composer. Add it to your project by running $ composer require bitandblack/request-cache.

Usage

At first initialize a cache type and a process object, and use them to initialize the request handler object. In this example we're going to use the FileSystemCache:

<?php

use BitAndBlack\RequestCache\CacheType\FileSystemCache;
use BitAndBlack\RequestCache\Process;
use BitAndBlack\RequestCache\RequestHandler;

$cache = new FileSystemCache(__DIR__);
$process = new Process();
$requestHandler = new RequestHandler($cache, $process);

The request handler is now ready to be used. Now create a request object with the URL you want to request and the time to live (ttl). This example requests the URL https://www.bitandblack.com and allows the data to be stored for 1 hour:

<?php

use BitAndBlack\RequestCache\Request;

$request = new Request(
    'https://www.bitandblack.com',
    3600
);

The data can be requested now:

<?php

$response = $requestHandler->getResponse($request);

The request handler will return the response immediately and without blocking the script:

  • If the requested URL has been cached and is still valid, the cached response is returned.
  • If it has been cached but is expired, the last response is returned while the new data is requested in the background (stale-while-revalidate).
  • If nothing has been cached yet, your default value is returned right away and the data is requested in the background, so the next call is fast.

When successful, the response will be a Psr\Http\Message\ResponseInterface object. The concrete implementation is provided by your PSR-17 response factory (see below).

If you want to block until the network answer arrives anyway — for example to fill the cache during a warm-up — pass true as the third argument: $requestHandler->getResponse($request, null, true). The PSR-18 compatible sendRequest() method does the same.

HTTP implementation

This library does not depend on a specific HTTP client. Instead, it uses php-http/discovery to find an installed PSR-18 client and PSR-17 factories at runtime. Any package that provides a psr/http-client-implementation or a psr/http-factory-implementation works out of the box, for example:

$ composer require guzzlehttp/guzzle
# or
$ composer require symfony/http-client nyholm/psr7

Requirements

The background request is executed by a separate PHP CLI process, so the following must be available in your environment:

  • A php CLI binary (the path can be configured when instantiating the Process object).
  • The exec() function (and popen() on Windows) must not be disabled in your php.ini.
  • The background process must be able to load Composer's vendor/autoload.php.

Options

Custom request client

Per default, the request client and the request/stream factories are resolved via HTTP Discovery. You can use the request callback to set up a custom request client or to modify the configuration.

<?php

use GuzzleHttp\Client;
use Psr\Http\Message\ResponseInterface;

$cache->setRequestCallback(
    function (string $url): ResponseInterface 
    {
        $client = new Client();
        return $client->request(
            'GET',
            $url,
            [
                'allow_redirects' => false
            ]
        );
    }
);

TTL

The ttl value may be easier to set with the help of the bitandblack/duration library. For example instead of writing 86400 for the duration of a whole day, you can write Duration::createFromDays(1)->getSeconds() then.

Help

If you have any questions, feel free to contact us under hello@bitandblack.com.

Further information about Bit&Black can be found under www.bitandblack.com.