haspadar / carl
Immutable object-oriented curl wrapper for PHP
v0.9.0
2025-09-22 10:26 UTC
Requires
- php: 8.4.*
- ext-curl: *
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3
- infection/infection: ^0.31
- nunomaduro/collision: ^8.8
- phpmetrics/phpmetrics: ^3.0
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^12.2
- psalm/plugin-phpunit: ^0.19.5
- rector/rector: ^2.1
- roave/security-advisories: dev-latest
- vimeo/psalm: ^6.10
- dev-main
- v0.9.0
- v0.8.0
- v0.7.0
- v0.6.0
- v0.5.0
- v0.4.0
- v0.3.0
- v0.2.0
- dev-feature/fake-response-defaults
- dev-feat/fake-response-info-headers
- dev-feat/response-decorators
- dev-fix/throttled-client-chunk-delay
- dev-release/v0.6.0
- dev-feature/composite-reaction
- dev-feat/limited-client
- dev-fix/curl-info-strings
- dev-with-form-body
- dev-waiting-server
- dev-chenked-client-with-iterable
- dev-response-tests-v2
- dev-request-tests
- dev-http-assert-traits
- dev-php-server
- dev-response-tests
- dev-reaction-tests
- dev-outcomes-tests
- dev-fake-responses
- dev-review/clean
This package is auto-updated.
Last update: 2025-09-22 10:30:22 UTC
README
Immutable HTTP client for PHP built on cURL. Pure OOP, no null
, no static
.
Inspired by Elegant Objects and cactoos.
Features
- Final, immutable classes with single responsibility
- No
null
values anywhere - No
static
methods or state - Lazy evaluation of HTTP requests
- Built-in fake clients and responses for testing
- No external dependencies except PHP and cURL
Simple Request Example
$response = new CurlClient()->outcome( new GetRequest('https://httpbin.org/get') )->response(); echo $response->body();
Parallel Requests with onSuccess and onFailure
$client = new CurlClient(); $requests = [ new GetRequest('https://httpbin.org/status/200'), new GetRequest('https://httpbin.org/status/404'), ]; $outcomes = $client->outcomes($requests, new class implements Reaction { public function onSuccess(Request $request, Response $response): void { echo "Success: " . $response->body() . "\n"; } public function onFailure(Request $request, string $error): void { echo "Failure: " . $error . "\n"; } }); +Note: CurlClient returns outcomes in completion order (not request order).
๐งช Testing with Fakes
Carl provides fake classes for isolated unit testing without real HTTP calls. You can replace the real client with FakeClient
to drive predefined outcomes.
Examples of fake outcomes:
AlwaysSuccessful
โ always returns success (HTTP 200)AlwaysFails
โ always returns a failure with a given error messageCycle
โ cycles through a list of outcomes in orderFakeStatus
โ returns an outcome with HTTP status code derived from the URI path
Example usage:
new FakeClient(new Cycle([ new AlwaysSuccessful(new SuccessResponse("OK")), new AlwaysFails("network error"), ]))->outcomes( [ new GetRequest('https://example.com/a'), new GetRequest('https://example.com/b'), ], new OnSuccessResponse( fn (Response $response) => print $response->body() ) ); // Sequence: OK, error, OK, error, ...
๐ค Lazy Evaluation
Carl objects are lightweight and perform no heavy work in constructors. Network I/O occurs only when you call outcome()
or outcomes()
. Response parsing/consumption (e.g., body()
) is deferred until you access it. This keeps composition predictable and fast.
๐ฅ Installation
composer require haspadar/carl
$response = new CurlClient()->outcome( new GetRequest('https://httpbin.org/get') )->response(); echo $response->body();
Requirements
- PHP 8.4+
- ext-curl (enabled by default in most PHP distributions)