Changing Client
One of the core design goals of this package is driver independence. You write your request code once, and the underlying HTTP library can be swapped at any time -- through configuration, the builder, or direct injection. This is especially valuable when moving between environments (e.g., a Symfony project that uses the Symfony driver vs. a CLI tool that uses raw cURL).
Available Drivers¶
The package ships with three production drivers and one test driver:
| Driver name | Library | Package |
|---|---|---|
curl |
PHP cURL extension | Built-in (no dependency) |
guzzle |
Guzzle HTTP | guzzlehttp/guzzle |
symfony |
Symfony HttpClient | symfony/http-client |
| (mock) | Built-in test double | Built-in |
The default driver is curl, which requires no additional dependencies since the cURL extension is included with most PHP installations.
CurlDriver¶
The cURL driver provides zero-dependency HTTP support. It uses PHP's native cURL extension with automatic HTTP/1.1 and HTTP/2 negotiation, full header parsing, streaming support, and built-in SSL verification. This is the best choice for quick starts and lightweight applications.
GuzzleDriver¶
Guzzle is a mature, feature-rich HTTP client with its own middleware ecosystem, PSR-7 message support, and excellent streaming capabilities. Use it when you need Guzzle-specific features or when your project already depends on it.
SymfonyDriver¶
The Symfony HttpClient offers native HTTP/2 support, automatic content-type detection, and multiple transports (native PHP, cURL, amphp). It is the natural choice for Symfony applications.
Switching Drivers¶
Via Configuration¶
The simplest way to choose a driver is through HttpClientConfig:
use Cognesy\Http\Config\HttpClientConfig;
use Cognesy\Http\HttpClient;
// Use Guzzle
$client = HttpClient::fromConfig(new HttpClientConfig(driver: 'guzzle'));
// Use Symfony
$client = HttpClient::fromConfig(new HttpClientConfig(driver: 'symfony'));
// Use cURL (default)
$client = HttpClient::fromConfig(new HttpClientConfig(driver: 'curl'));
Via the Builder¶
The builder gives you the same choice in a more explicit, composable form:
use Cognesy\Http\Config\HttpClientConfig;
use Cognesy\Http\Creation\HttpClientBuilder;
$client = (new HttpClientBuilder())
->withConfig(new HttpClientConfig(driver: 'guzzle'))
->create();
Injecting a Driver Directly¶
If you have a pre-configured driver instance, bypass the registry entirely:
use Cognesy\Http\Creation\HttpClientBuilder;
$client = (new HttpClientBuilder())
->withDriver($myCustomDriver)
->create();
Or use the static shorthand:
Reusing a Vendor Client Instance¶
Sometimes you already have a configured vendor client (e.g., a GuzzleHttp\Client with custom options or a Symfony client with specific transport settings). You can pass that instance directly:
use Cognesy\Http\Creation\HttpClientBuilder;
use GuzzleHttp\Client;
$guzzle = new Client([
'timeout' => 10,
'verify' => '/path/to/cacert.pem',
]);
$client = (new HttpClientBuilder())
->withClientInstance('guzzle', $guzzle)
->create();
The withClientInstance() method selects the driver by name and passes your vendor client to it, so the driver uses your instance instead of creating its own.
This works with any supported driver:
use Symfony\Component\HttpClient\HttpClient as SymfonyHttpClient;
$client = (new HttpClientBuilder())
->withClientInstance('symfony', SymfonyHttpClient::create(['timeout' => 30]))
->create();
Using the Mock Driver¶
For testing, the mock driver lets you define responses without making network calls:
use Cognesy\Http\Creation\HttpClientBuilder;
use Cognesy\Http\Data\HttpResponse;
$client = (new HttpClientBuilder())
->withMock(function ($mock) {
$mock->addResponse(
HttpResponse::sync(200, ['Content-Type' => 'application/json'], '{"users":[]}'),
url: 'https://api.example.com/users',
method: 'GET',
);
})
->create();
Request Code Stays the Same¶
The key insight is that your request code never changes when you switch drivers. The same HttpRequest, the same send() call, the same response handling:
$response = $client->send(new HttpRequest(
url: 'https://api.example.com/data',
method: 'GET',
headers: ['Accept' => 'application/json'],
body: '',
options: [],
))->get();
echo $response->body();
This code works identically with cURL, Guzzle, Symfony, or the mock driver.
See Also¶
- Changing Client Config -- configure timeouts, error handling, and stream settings.
- Custom Clients -- register your own driver when the bundled ones are not enough.