Skip to content

Client Configuration

Muhammet Şafak edited this page May 24, 2026 · 1 revision

Client Configuration

InitPHP\HTTP\Client\Client exposes five configuration knobs. Each has both a fluent set* mutator and an immutable with* wither.

Setting Default Mutator Wither
Request timeout 30 s setTimeout(int $seconds) withTimeout(int $seconds)
Connect timeout 10 s setConnectTimeout(int $seconds) withConnectTimeout(int $seconds)
Follow redirects true (up to 10 hops) setFollowRedirects(bool, int $max = 10) withFollowRedirects(bool, int $max = 10)
User-Agent 'InitPHP HTTP PSR-18 Client cURL' setUserAgent(?string) withUserAgent(?string)
Custom cURL opts [] setCurlOptions(array $options) withCurlOptions(array $options)
use InitPHP\HTTP\Client\Client;

$client = (new Client())
    ->withTimeout(15)
    ->withConnectTimeout(3)
    ->withFollowRedirects(true, 5)
    ->withUserAgent('my-service/1.0')
    ->withCurlOptions([
        CURLOPT_CAINFO         => '/etc/ssl/certs/ca-bundle.crt',
        CURLOPT_PROXY          => 'http://proxy.internal:3128',
        CURLOPT_SSL_VERIFYPEER => true,
    ]);

set* vs with*

set* mutates the client in place and returns $this for chaining:

$client = new Client();
$client->setTimeout(15);     // $client now has timeout=15

with* returns a clone:

$client     = new Client();
$shortClient = $client->withTimeout(5);
// $client still has timeout=30; $shortClient has timeout=5

Pick the wither when the client is shared across many request paths and each path needs its own override. Pick the mutator when you're building the client once at boot.

Timeouts

CURLOPT_TIMEOUT = 0 disables the timeout entirely. The package's default of 30 s exists because a runaway request will tie up a PHP-FPM worker indefinitely otherwise — production HTTP clients without a timeout are an outage waiting to happen.

If you really need an infinite wait (long-poll, server-sent events), be explicit:

$longPoll = $client->withTimeout(0)->withConnectTimeout(10);

The connect timeout is separate from the total timeout. CURLOPT_CONNECTTIMEOUT = 10 means we'll spend at most 10 s establishing the TCP/TLS handshake before failing fast; the remaining time budget is reserved for the response.

Redirects

// default — follow up to 10 redirects
$client->withFollowRedirects(true);

// follow up to 3 redirects
$client->withFollowRedirects(true, 3);

// don't follow at all (caller handles 3xx)
$client->withFollowRedirects(false);

When following is on, the returned Response is the final leg only — intermediate responses are not exposed.

User-Agent

$client->setUserAgent('my-service/1.0 (+https://example.com/contact)');

Setting null or the empty string is a no-op — the User-Agent is never cleared by these methods. If you really need an empty User-Agent, do it at the request level ($request->withHeader('User-Agent', '')) which is what gets emitted to the wire.

Custom cURL options — the escape hatch

curlOptions are merged on top of the per-request defaults (URL, headers, body, timeouts, ...) last-write-wins. So an override here wins over the explicit knobs above; reach for this sparingly.

Useful patterns:

// Force SNI for self-signed cert testing
[CURLOPT_RESOLVE => ['api.example.test:443:127.0.0.1']]

// Pin TLS version
[CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_3]

// Capture verbose debug output
[CURLOPT_VERBOSE => true, CURLOPT_STDERR => fopen('php://stderr', 'w')]

// Bind to a specific local interface
[CURLOPT_INTERFACE => '203.0.113.10']

// HTTP/3 (if your cURL build supports it)
[CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_3]

A note on retries

This client does not implement automatic retries. PSR-18 leaves retry policy entirely to the caller — different callers want different policies (linear backoff, exponential backoff, idempotency keys, circuit breakers, ...). Wrap the client in your own retry loop when you need it:

function retry(\Psr\Http\Client\ClientInterface $client, RequestInterface $request, int $tries = 3, int $delayMs = 500): ResponseInterface
{
    $last = null;
    for ($i = 0; $i < $tries; $i++) {
        try {
            $response = $client->sendRequest($request);
            if ($response->getStatusCode() < 500) {
                return $response;
            }
            $last = new RuntimeException('upstream ' . $response->getStatusCode());
        } catch (\Psr\Http\Client\NetworkExceptionInterface $e) {
            $last = $e;
        }
        usleep($delayMs * 1000 * (2 ** $i));
    }
    throw $last;
}

See also

Clone this wiki locally