Class
HttpClient
A PSR-18 HTTP client that runs concurrent requests on curl_multi.
Introduction#
sendRequest() follows PSR-18: it returns once the response headers have arrived, or throws a
Psr\Http\Client\ClientExceptionInterface: RequestException for an invalid request,
NetworkException when no response arrives because of a network failure, and
ClientException for any other failure. Inside a coroutine only the calling coroutine is
suspended while it waits; outside one the call blocks until the response has arrived. The body
keeps streaming after it returns, and a failure while reading it is thrown from the stream read.
An HTTP error status such as 404 or 500 is a normal response and throws nothing.
sendAsyncRequest(), get(), post(), put() and request() are not PSR-18: they return a CurlResponse at
once, before the transfer has started, so that several requests can run together. The transfer
starts when the response's status, headers or body is first read, every request created up to
then starts together, and a failure is thrown by that first read.
Cancelling a coroutine that is waiting for a response throws phasync\CancelledException in it.
The client stays usable.
Class synopsis#
final class HttpClient implements ClientInterface {
/* Methods */
public HttpClient::__construct(HttpClientOptions|array $defaultRequestOptions = [])
public HttpClient::addMiddlewareFunction(Closure $middleware): void
public HttpClient::sendRequest(RequestInterface $request): ResponseInterface
public HttpClient::sendAsyncRequest(RequestInterface $request): ResponseInterface
public HttpClient::request(
string $method,
UriInterface|string $url,
mixed $requestData = null,
HttpClientOptions|array|null $options = null
): ResponseInterface
public HttpClient::get(
UriInterface|string $url,
HttpClientOptions|array|null $options = null
): ResponseInterface
public HttpClient::post(
UriInterface|string $url,
mixed $requestData,
HttpClientOptions|array|null $options = null
): ResponseInterface
public HttpClient::put(
UriInterface|string $url,
mixed $requestData,
HttpClientOptions|array|null $options = null
): ResponseInterface
}Methods#
| Method | Description |
|---|---|
__construct | Create a client whose options are the defaults for every request it sends. |
addMiddlewareFunction | Wrap HttpClient::sendRequest in a function that can change the request or the response. |
sendRequest | Send a PSR-7 request with the client's default options. |
sendAsyncRequest | Send a PSR-7 request without waiting: the lazy counterpart of HttpClient::sendRequest. |
request | Send a request with any method, a body and options for this request only. |
get | Send a GET request. |
post | Send a POST request with a body. |
put | Send a PUT request with a body. |
Examples#
use phasync\HttpClient\HttpClient;
$base = require __DIR__ . '/../server.php'; // a local server for the example
$client = new HttpClient(['timeoutMs' => 5000]);
// Neither transfer has started yet: both start together at the first read
$slow = $client->get("$base/slow?seconds=0.2&name=slow");
$fast = $client->get("$base/slow?seconds=0.1&name=fast");
echo $slow->getStatusCode(), ' ', $slow->getBody(), "\n";
echo $fast->getStatusCode(), ' ', $fast->getBody(), "\n";200 slow 200 fast
use phasync\HttpClient\HttpClient;
$base = require __DIR__ . '/../server.php';
$client = new HttpClient();
// Inside phasync::run() a request suspends only the coroutine that waits for it
phasync::run(function () use ($client, $base) {
foreach (['b' => 0.2, 'a' => 0.1] as $name => $seconds) {
phasync::go(function () use ($client, $base, $name, $seconds) {
$body = (string) $client->get("$base/slow?seconds=$seconds&name=$name")->getBody();
echo "response $body\n";
});
}
echo "both requests sent\n";
});both requests sent response a response b
use phasync\HttpClient\HttpClient;
$client = new HttpClient(['timeoutMs' => 5000]);
// Neither transfer has started yet, so both run at the same time once the first is read.
$a = $client->get('https://example.com/a');
$b = $client->get('https://example.com/b');
echo $a->getStatusCode(), "\n";
echo $b->getBody();
// PSR-18: returns when the headers have arrived, or throws.
try {
$response = $client->sendRequest(\phasync\Psr\Request::create('GET', 'https://example.com/c'));
} catch (\Psr\Http\Client\NetworkExceptionInterface $e) {
echo 'no response: ', $e->getMessage();
}See also#
HttpClient::requestSend a request with any method, a body and options for this request only.HttpClientOptionsThe options of an HTTP request, as public properties that map to cURL options.CurlResponseThe PSR-7 response of anHttpClientrequest, filled in by a cURL transfer.NetworkExceptionNo response arrived, or the response stopped arriving, because of a network failure.RequestExceptionThe request could not be sent because it is invalid.ClientExceptionA request failed for a reason that is neither an invalid request nor a network failure.MultipartStreamAmultipart/form-datarequest body built from a nested array of fields.phasync::goStarts$fnas a coroutine in the current frame and scope, and returns it, without waiting for it.